diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index b9f69412..23d3744b 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,11 +3,11 @@ "isRoot": true, "tools": { "csharpier": { - "version": "1.0.1", + "version": "1.1.2", "commands": [ "csharpier" ], "rollForward": false } } -} \ No newline at end of file +} diff --git a/.csharpierignore b/.csharpierignore new file mode 100644 index 00000000..e69fe35c --- /dev/null +++ b/.csharpierignore @@ -0,0 +1,2 @@ +*.csproj +*.props diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..00e36898 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,12 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name": "C# (.NET)", + "image": "mcr.microsoft.com/devcontainers/dotnet:1-9.0-noble", + "postAttachCommand": "cat .vscode/extensions.json | jq -r .recommendations[] | xargs -n 1 code --install-extension", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + "features": { + // For the Prism mock server. + "ghcr.io/devcontainers/features/node:1": {} + } +} diff --git a/.editorconfig b/.editorconfig index 0ba6c1e6..ca50e033 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,4 +23,12 @@ insert_final_newline = true dotnet_diagnostic.IDE0060.severity = none # Caused by resource with no methods and no subresources dotnet_diagnostic.IDE1006.severity = none # Some names may not match up with C# conventions -dotnet_diagnostic.IDE0290.severity = none # Don't prefer primary constructors \ No newline at end of file +dotnet_diagnostic.IDE0290.severity = none # Don't prefer primary constructors +dotnet_diagnostic.IDE0028.severity = none # "Collection initialization can be simplified" is a bit overzealous +dotnet_diagnostic.IDE0090.severity = none # "Simplify 'new' expression" is a bit overzealous + +# For .NET Standard 2.0 support +dotnet_diagnostic.IDE0057.severity = none # Caused by use of `.Substring(...)` +dotnet_diagnostic.CA1866.severity = none # Caused by use of `.StartsWith(...)` with single character string +dotnet_diagnostic.CA1847.severity = none # Caused by use of `.Contains(...)` with single character string +dotnet_diagnostic.CA2263.severity = none # Caused by use of non-generic `Enum.IsDefined(...)` diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a069dcc..1faf4d1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,13 +27,17 @@ jobs: with: dotnet-version: '8.0.x' + - name: Run bootstrap + run: ./scripts/bootstrap + - name: Run lints run: ./scripts/lint - test: + build: timeout-minutes: 10 - name: test + name: build runs-on: ${{ github.repository == 'stainless-sdks/orb-csharp' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + steps: - uses: actions/checkout@v4 @@ -42,5 +46,21 @@ jobs: with: dotnet-version: '8.0.x' + - name: Build SDK + run: ./scripts/build + + test: + timeout-minutes: 10 + name: test + runs-on: ${{ github.repository == 'stainless-sdks/orb-csharp' && 'depot-windows-2022' || 'windows-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '8.0.x' + - name: Run tests run: ./scripts/test diff --git a/.gitignore b/.gitignore index cd42ee34..08a6d808 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ +.prism.log bin/ obj/ +.vs/ +.idea/ diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..3d2ac0bd --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.1.0" +} \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 9450f45c..427fe5b6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 116 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-612316c13276a207f56e2e2c7bbc68f4bb73de85e3661595a23f23d9ccc80276.yml -openapi_spec_hash: 6e125f05e40521ec485edf6e15beec2e -config_hash: 8c9a47f104c777e2a1e8f3fad15c093b +configured_endpoints: 118 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-647fcb5866bd752a09db1530acb79134f9cc729b2e00d9abecc0b60806183817.yml +openapi_spec_hash: 080cc78660e0a91499a46ef8bf0a3745 +config_hash: 05c94c0e6dbeab2c9b554c2e0d6371a0 diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..921dd6d6 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "ms-dotnettools.csharp", + "editorconfig.editorconfig", + "github.vscode-github-actions", + "ms-dotnettools.vscode-dotnet-runtime", + "ms-dotnettools.csdevkit" + ], + "unwantedRecommendations": [] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..44e8da69 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,190 @@ +# Changelog + +## 0.1.0 (2025-12-28) + +Full Changelog: [v0.0.1...v0.1.0](https://github.com/orbcorp/orb-csharp/compare/v0.0.1...v0.1.0) + +### ⚠ BREAKING CHANGES + +* **client:** add pagination +* **client:** use readonly types for properties +* **client:** improve names of some types +* **client:** use `DateTimeOffset` instead of `DateTime` +* **client:** flatten service namespaces +* **client:** interpret null as omitted in some properties +* **client:** make models immutable +* **api:** define shared model ConversionRateConfig + +### Features + +* **api:** add C# ([e2db41d](https://github.com/orbcorp/orb-csharp/commit/e2db41d4c0585fc2e3472df2a88a5be4cb2432fb)) +* **api:** api update ([fb72da9](https://github.com/orbcorp/orb-csharp/commit/fb72da955561c151b2c2692942b6b5fcc1ae1377)) +* **api:** api update ([4ccd578](https://github.com/orbcorp/orb-csharp/commit/4ccd578bd3ebad15d494aac683df4c9257bbe70a)) +* **api:** api update ([f90e3ae](https://github.com/orbcorp/orb-csharp/commit/f90e3aeb62544116e49684b6c9951c0c945341a2)) +* **api:** api update ([1a56902](https://github.com/orbcorp/orb-csharp/commit/1a569028014ee7a24fed29298ea9d2f87b047ef6)) +* **api:** api update ([64ba8ff](https://github.com/orbcorp/orb-csharp/commit/64ba8ff04267925ec36852f5bd0a819a0e80c110)) +* **api:** api update ([9ddf9be](https://github.com/orbcorp/orb-csharp/commit/9ddf9beeb5cc4fca7c308220c4a0820c1e6ade2c)) +* **api:** api update ([517311a](https://github.com/orbcorp/orb-csharp/commit/517311a6b269d832f4d5759ce6b3b2a681d3715e)) +* **api:** api update ([d6db301](https://github.com/orbcorp/orb-csharp/commit/d6db301d92a13f9da964825748a976414357cbc6)) +* **api:** api update ([baf08f2](https://github.com/orbcorp/orb-csharp/commit/baf08f2a636733826d01ea04ce08e8d55dbedd34)) +* **api:** api update ([df68529](https://github.com/orbcorp/orb-csharp/commit/df68529c628bfd38011000ef2e2dcdb943cb7e48)) +* **api:** api update ([8a73d24](https://github.com/orbcorp/orb-csharp/commit/8a73d245379717e0ab1f9011687146fd70b51d18)) +* **api:** api update ([a369ef4](https://github.com/orbcorp/orb-csharp/commit/a369ef4411504f1b649068102ee2b98ee0039e31)) +* **api:** api update ([9e6c001](https://github.com/orbcorp/orb-csharp/commit/9e6c0010cda481a36f2fbdea2d342f142e85caba)) +* **api:** api update ([9504b00](https://github.com/orbcorp/orb-csharp/commit/9504b005a855d7d1e7281db5e317f961651f41e0)) +* **api:** api update ([713ee01](https://github.com/orbcorp/orb-csharp/commit/713ee01200d14436e8059e31ea6b2e46aae2cc27)) +* **api:** api update ([7f1811a](https://github.com/orbcorp/orb-csharp/commit/7f1811ac69511ae361e1dca3ba674e09c8543fdd)) +* **api:** api update ([5c02e33](https://github.com/orbcorp/orb-csharp/commit/5c02e33ae1bf78f394826bf8ee944e57ea267ed9)) +* **api:** api update ([090a2e3](https://github.com/orbcorp/orb-csharp/commit/090a2e381704c21336187dacb90d6d2d58b02d92)) +* **api:** api update ([1d104ef](https://github.com/orbcorp/orb-csharp/commit/1d104efdab8d54aab1f7f3faabc14340a1712592)) +* **api:** api update ([9251b92](https://github.com/orbcorp/orb-csharp/commit/9251b924af640affef0978e2ee480d166404ab56)) +* **api:** api update ([8108e0d](https://github.com/orbcorp/orb-csharp/commit/8108e0dcd3ad5307a3a9892f531a2f8f9f0da63f)) +* **api:** api update ([6cf340c](https://github.com/orbcorp/orb-csharp/commit/6cf340c42fe835582097d76138e146a9b866848b)) +* **api:** api update ([e4c3bc5](https://github.com/orbcorp/orb-csharp/commit/e4c3bc54e4ede4af023580d236a576f138030d51)) +* **api:** api update ([9496bca](https://github.com/orbcorp/orb-csharp/commit/9496bca600fed4c446eeb2ae733e96ad1bdd7037)) +* **api:** api update ([abb7452](https://github.com/orbcorp/orb-csharp/commit/abb74522112928e627b15244dfdfb30c59ddf275)) +* **api:** api update ([ce002f9](https://github.com/orbcorp/orb-csharp/commit/ce002f96f261a51969f208050ec60efe8c731667)) +* **api:** api update ([d0978b0](https://github.com/orbcorp/orb-csharp/commit/d0978b09eddaf187445fefda66fa638a7e23d8c0)) +* **api:** api update ([6a36022](https://github.com/orbcorp/orb-csharp/commit/6a360220ec6166a37a449e422de14e1f550a25e1)) +* **api:** api update ([1f8e15d](https://github.com/orbcorp/orb-csharp/commit/1f8e15dd5052bdaba7cf123fca6212ae4b805803)) +* **api:** api update ([d0e9264](https://github.com/orbcorp/orb-csharp/commit/d0e9264c44939b5266f32d6d7422470a9ef73498)) +* **api:** api update ([2c673c4](https://github.com/orbcorp/orb-csharp/commit/2c673c4ae6223e96418d3726c484a8b5a5fe338f)) +* **api:** api update ([529c386](https://github.com/orbcorp/orb-csharp/commit/529c38605cf3f39b34bc35f4d991251e93fc012c)) +* **api:** api update ([7e10ed7](https://github.com/orbcorp/orb-csharp/commit/7e10ed7e6662fbe98d4d5a71be4207a05e9a9610)) +* **api:** api update ([f13e7df](https://github.com/orbcorp/orb-csharp/commit/f13e7df64231245e19291d780631124aef62e9ac)) +* **api:** api update ([b08df82](https://github.com/orbcorp/orb-csharp/commit/b08df824c44e6cc0ac72d42b07c3c089f501862d)) +* **api:** api update ([d0d1a79](https://github.com/orbcorp/orb-csharp/commit/d0d1a7995095b23506e98a0ba0e5bdb47370dc5f)) +* **api:** api update ([268fdab](https://github.com/orbcorp/orb-csharp/commit/268fdab77f42a6e87ffc2f7fd1863bbd05d30033)) +* **api:** api update ([7c7a621](https://github.com/orbcorp/orb-csharp/commit/7c7a621be47edaca08972e0986c72dab410ec052)) +* **api:** define shared model ConversionRateConfig ([8420455](https://github.com/orbcorp/orb-csharp/commit/84204551c212283c5fe0568e46f8ea88b9ec1d17)) +* **client:** add `HttpResponse.ReadAsStream` method ([3a51242](https://github.com/orbcorp/orb-csharp/commit/3a51242c08032d7df6c2ded8dcce4d7461309b16)) +* **client:** add additional implicit conversions ([32d7f99](https://github.com/orbcorp/orb-csharp/commit/32d7f99de2587b6562e65cb04f56bfc63d154c9a)) +* **client:** add cancellation token support ([d322904](https://github.com/orbcorp/orb-csharp/commit/d32290447d4e2efc41558d5f7d36fd64e353636a)) +* **client:** add EnvironmentUrl ([1bfe99f](https://github.com/orbcorp/orb-csharp/commit/1bfe99f1ec23576f124a80532c2bdc8d267cdbc1)) +* **client:** add multipart form data support ([b072c6b](https://github.com/orbcorp/orb-csharp/commit/b072c6b1b261c953599a90fc9966473c96662e63)) +* **client:** add pagination ([124e833](https://github.com/orbcorp/orb-csharp/commit/124e8337ea796d38adf41695a5c8ff595cf7261d)) +* **client:** add response validation option ([dda33ed](https://github.com/orbcorp/orb-csharp/commit/dda33ed46fa48b74ad6e33a92a514f9e073b4417)) +* **client:** add retries support ([006167f](https://github.com/orbcorp/orb-csharp/commit/006167f9f261f30f862b668b4069855fc1667799)) +* **client:** add some convenience constructors ([8e82a6b](https://github.com/orbcorp/orb-csharp/commit/8e82a6b10a0d13a256c4a330e4fcd159c1b791dc)) +* **client:** add some implicit operators ([b7bb4f2](https://github.com/orbcorp/orb-csharp/commit/b7bb4f29cb1948682215cdee52f92de7704dbe82)) +* **client:** add support for option modification ([585182a](https://github.com/orbcorp/orb-csharp/commit/585182ac828f3c32a7efd9df0f604d7e3db407da)) +* **client:** add x-stainless-retry-count ([d4caa5e](https://github.com/orbcorp/orb-csharp/commit/d4caa5efe4e7003df784aeb64e2817a5ac4b9374)) +* **client:** additional methods for positional params ([965ec12](https://github.com/orbcorp/orb-csharp/commit/965ec12761ede2c41d2ae3f708ef5baa3d84a625)) +* **client:** automatically set constants for user ([25e678a](https://github.com/orbcorp/orb-csharp/commit/25e678a352492d8119389201e754ffa1b96b85a0)) +* **client:** implement implicit union casts ([5a6d432](https://github.com/orbcorp/orb-csharp/commit/5a6d4322fd6e82838a22f6658a6252f0c76bf367)) +* **client:** improve csproj ([284ef6e](https://github.com/orbcorp/orb-csharp/commit/284ef6eb1b68e376df2cd43aa4518bf1a01900d6)) +* **client:** improve model names ([df035d1](https://github.com/orbcorp/orb-csharp/commit/df035d1ec73f8ce1226571a18732529a91eba08d)) +* **client:** improve some names ([7692fdd](https://github.com/orbcorp/orb-csharp/commit/7692fdd57bc7478737dc012ec2a37996b5b82f50)) +* **client:** make models immutable ([22921ae](https://github.com/orbcorp/orb-csharp/commit/22921ae7a1c1885ef8302a5e0242aab867a2d005)) +* **client:** refactor exceptions ([74c487d](https://github.com/orbcorp/orb-csharp/commit/74c487d14332d0adadd917b417b5bb8bd25f315e)) +* **client:** refactor unions ([bab0e94](https://github.com/orbcorp/orb-csharp/commit/bab0e9426a803f3ffe83f075ba3245b6e63ef389)) +* **client:** send `User-Agent` header ([d9f32d8](https://github.com/orbcorp/orb-csharp/commit/d9f32d8da6c447e811eba35d9f089b3c453f1831)) +* **client:** send `X-Stainless-Arch` header ([11b2877](https://github.com/orbcorp/orb-csharp/commit/11b28775f28ce6df4a0150c19b15a8253f341e19)) +* **client:** send `X-Stainless-Lang` and `X-Stainless-OS` headers ([ff4a7fe](https://github.com/orbcorp/orb-csharp/commit/ff4a7fe314c413be2cab0dbc20a9439cfcc272eb)) +* **client:** send `X-Stainless-Package-Version` headers ([d3b8497](https://github.com/orbcorp/orb-csharp/commit/d3b8497a2b079f26e68b76dca338bf9636ba2107)) +* **client:** send `X-Stainless-Runtime` and `X-Stainless-Runtime-Version` ([a49e832](https://github.com/orbcorp/orb-csharp/commit/a49e832192f9e72bc7219b2a96257e6b673e5c3b)) +* **client:** send `X-Stainless-Timeout` header ([569bcb2](https://github.com/orbcorp/orb-csharp/commit/569bcb24b6ab3136d365c9bc09eb8fc48a3cfab6)) +* **client:** support .NET Standard 2.0 ([a13a7da](https://github.com/orbcorp/orb-csharp/commit/a13a7da53e8dd58c539da7017e79d20fdf3f4fb8)) +* **client:** support request timeout ([3ec7070](https://github.com/orbcorp/orb-csharp/commit/3ec7070902494de24e591ae1c8e65f57a9568146)) +* **client:** use strings for date/time ([b2a0df7](https://github.com/orbcorp/orb-csharp/commit/b2a0df7323102a7ec52cc7de497717d7a8f975f9)) +* **client:** validate constant values ([e9ab518](https://github.com/orbcorp/orb-csharp/commit/e9ab518b3348e1c90973c5cdeda5e95b7fc5d8df)) +* extract minimum composite to type ([0b9eedc](https://github.com/orbcorp/orb-csharp/commit/0b9eedc8db21cc0cd2835ecc479c5adfd4069bb1)) +* **internal:** add additional object tests ([58e230c](https://github.com/orbcorp/orb-csharp/commit/58e230c9a2c49e4c5007d6776116285a501016b0)) +* **internal:** add dev container ([cd5e090](https://github.com/orbcorp/orb-csharp/commit/cd5e09074dae5d0de3f41a1b9de196d7dffa185b)) +* **internal:** generate release flow files ([3eb9334](https://github.com/orbcorp/orb-csharp/commit/3eb9334def8a6d9e09154e9c3d606f42897379fa)) + + +### Bug Fixes + +* **client:** check response status when `MaxRetries = 0` ([54eb187](https://github.com/orbcorp/orb-csharp/commit/54eb187822acb7162a4c6ebe8af224653b164a37)) +* **client:** deprecate some constructors ([7ca3eea](https://github.com/orbcorp/orb-csharp/commit/7ca3eeaae1f7588a1efc454feab9b579aa910deb)) +* **client:** handle multiple auth options gracefully ([ab63f1e](https://github.com/orbcorp/orb-csharp/commit/ab63f1e93a46234075928aef1058aff4ca49b8bb)) +* **client:** handling of null value type ([af22d1e](https://github.com/orbcorp/orb-csharp/commit/af22d1e5661e63d2fdf0480f34c0b7fcff012966)) +* **client:** interpret null as omitted in some properties ([15855b6](https://github.com/orbcorp/orb-csharp/commit/15855b69d48025023ca07b3adcf17d5622ea6a34)) +* **client:** use `DateTimeOffset` instead of `DateTime` ([aa4b2f8](https://github.com/orbcorp/orb-csharp/commit/aa4b2f870a40fee63c2bbb46714a39ef4558f635)) +* **client:** use `JsonElement` in more places ([1de7a74](https://github.com/orbcorp/orb-csharp/commit/1de7a748678db6d4ad7a6f1214cae244579b53f0)) +* **client:** use readonly types for properties ([8b7b709](https://github.com/orbcorp/orb-csharp/commit/8b7b709089f067b4f6b1c380791e37d0074cea9a)) +* **client:** with expressions for models ([8a3cdcf](https://github.com/orbcorp/orb-csharp/commit/8a3cdcfdebad1f4dfb5776b8e433eb14f0d917a3)) +* **internal:** add nullability checks for tests ([1df879b](https://github.com/orbcorp/orb-csharp/commit/1df879b7489888342a782bb4c320c1216c0e436a)) +* **internal:** don't format csproj files ([7f5768a](https://github.com/orbcorp/orb-csharp/commit/7f5768adbb7da246537abd650b366f3bb866c73a)) +* **internal:** improve dictionary instantiation ([0dbc21b](https://github.com/orbcorp/orb-csharp/commit/0dbc21ba729634945379fbc9d6b83b7c3801d18b)) +* **internal:** install csharpier during ci lint phase ([9d24c26](https://github.com/orbcorp/orb-csharp/commit/9d24c26ad0bd6b72dea5c85043d76380518e6741)) +* **internal:** minor bug fixes on model instantiation and union validation ([f109cc7](https://github.com/orbcorp/orb-csharp/commit/f109cc7964841dabf67250ed78c77eb045c57e44)) +* **internal:** minor project fixes ([def9419](https://github.com/orbcorp/orb-csharp/commit/def9419ad3e99107e7b1bfd57239c72c21b8d089)) +* **internal:** prefer to use implicit instantiation when possible ([37366c3](https://github.com/orbcorp/orb-csharp/commit/37366c3e538f3923b5ecdcab2fc5118b348fc19a)) +* **internal:** remove example csproj ([66c1d05](https://github.com/orbcorp/orb-csharp/commit/66c1d05dbb85f1f327293b840baec4ff70371b6d)) +* **internal:** running net462 tests on ci ([c0a7fcc](https://github.com/orbcorp/orb-csharp/commit/c0a7fcc61428bf59f7ba854421a7f50bcf4efb56)) +* **internal:** test nullability warnings ([4b03b94](https://github.com/orbcorp/orb-csharp/commit/4b03b94e0f0fe56211981998dd4cfd34fc5b901c)) +* **internal:** various minor code fixes ([049b82c](https://github.com/orbcorp/orb-csharp/commit/049b82c0e2203f6d2731862c633806cb5b904c43)) +* **internal:** various smaller fixes ([2ff5c17](https://github.com/orbcorp/orb-csharp/commit/2ff5c174dec2ed0f3c10278eb2d67a68511e098f)) + + +### Performance Improvements + +* **client:** optimize header creation ([c17450e](https://github.com/orbcorp/orb-csharp/commit/c17450ee83ff7ce6091fbadc46e68ce760a42422)) +* **client:** use async deserialization in `HttpResponse` ([0466032](https://github.com/orbcorp/orb-csharp/commit/0466032107e12ee279d268df5b3c5fccf8a75593)) + + +### Chores + +* **client:** change name of underlying properties for models and params ([30fe818](https://github.com/orbcorp/orb-csharp/commit/30fe8180217f3d939b6c2ecc6bfe5f8f6046b554)) +* **client:** deprecate some symbols ([395ffe4](https://github.com/orbcorp/orb-csharp/commit/395ffe4bd0db51d6596833d44d66c9715623f282)) +* **client:** improve object instantiation ([5ad70e6](https://github.com/orbcorp/orb-csharp/commit/5ad70e6fdb4511e87bd3a30b01c56ad71903bfec)) +* **client:** improve union validation ([e3ba15d](https://github.com/orbcorp/orb-csharp/commit/e3ba15d89411d4b04eef20b8da6b01cedafdcc45)) +* **client:** simplify field validations ([dda33ed](https://github.com/orbcorp/orb-csharp/commit/dda33ed46fa48b74ad6e33a92a514f9e073b4417)) +* **client:** update test dependencies ([f8a3a59](https://github.com/orbcorp/orb-csharp/commit/f8a3a591f9780797631fb9cae74105db0438c73a)) +* **docs:** clarify beta library limitations in readme ([f4d1b52](https://github.com/orbcorp/orb-csharp/commit/f4d1b5253cdf0e3576547ecf7e78dcdf89b36a00)) +* **internal:** add enum tests ([4758f8b](https://github.com/orbcorp/orb-csharp/commit/4758f8b5b7ce9112603ae2fe9531f039a51131f4)) +* **internal:** add prism log file to gitignore ([35502d0](https://github.com/orbcorp/orb-csharp/commit/35502d01cf1fd2d78c920a0bb307487ad941e884)) +* **internal:** add union tests ([4169656](https://github.com/orbcorp/orb-csharp/commit/4169656b30cfe9b99332a295315e05e9c039fbca)) +* **internal:** codegen related update ([2a78b4a](https://github.com/orbcorp/orb-csharp/commit/2a78b4a7b38a2024be86de83207cf304232cfafa)) +* **internal:** codegen related update ([35d0ba7](https://github.com/orbcorp/orb-csharp/commit/35d0ba7fa2f347deeb85b97747a28af3cf3c4c66)) +* **internal:** codegen related update ([f1fe13a](https://github.com/orbcorp/orb-csharp/commit/f1fe13a8c19e2e8c044e51c31945043cf8cde5d5)) +* **internal:** codegen related update ([ad6f73f](https://github.com/orbcorp/orb-csharp/commit/ad6f73fca1ea274a68fbbe95f3cbd92669428242)) +* **internal:** equality and more unit tests ([fc3c17b](https://github.com/orbcorp/orb-csharp/commit/fc3c17b15fb6ab155145fab7deee5635938ecfc4)) +* **internal:** extract `ClientOptions` struct ([b7feea0](https://github.com/orbcorp/orb-csharp/commit/b7feea0be3d5b4e6968b6c17cb9cd36eba912e60)) +* **internal:** full qualify some references ([fc01a56](https://github.com/orbcorp/orb-csharp/commit/fc01a561cab014aba113de3d4ca4a91f05a2d54d)) +* **internal:** improve devcontainer ([ac0b263](https://github.com/orbcorp/orb-csharp/commit/ac0b263c044414e8893b0e856d583a9c6e514e7b)) +* **internal:** minor improvements to csproj and gitignore ([b153c54](https://github.com/orbcorp/orb-csharp/commit/b153c54462ceca807e7e57e97f078449649100c1)) +* **internal:** reduce import qualification ([73ff8de](https://github.com/orbcorp/orb-csharp/commit/73ff8de06a6ed5a03049c82ee7acfd41fc07b8fa)) +* **internal:** remove redundant keyword ([b214c47](https://github.com/orbcorp/orb-csharp/commit/b214c479fafa2ad92f224ae6b04e19ba37f0c421)) +* **internal:** restructure some imports ([d7fe315](https://github.com/orbcorp/orb-csharp/commit/d7fe31598d52037df273fbf71d025f7df90e5c44)) +* **internal:** share csproj properties with dir build props ([4b03b94](https://github.com/orbcorp/orb-csharp/commit/4b03b94e0f0fe56211981998dd4cfd34fc5b901c)) +* **internal:** suppress diagnostic for .netstandard2.0 ([4934a71](https://github.com/orbcorp/orb-csharp/commit/4934a713e438337d77ec404dd523e2a2616221d4)) +* **internal:** turn off overzealous lints ([1d0fcb0](https://github.com/orbcorp/orb-csharp/commit/1d0fcb083fdb3f5f769ec06d93958a20df850a18)) +* **internal:** update csproj formatting ([1bfa8ec](https://github.com/orbcorp/orb-csharp/commit/1bfa8ecda17df4b01b03e41ff5ae78e739b115aa)) +* **internal:** update release please config ([e7a5617](https://github.com/orbcorp/orb-csharp/commit/e7a561740b4918fced68e45ab3f4a58aa45a5f50)) +* **internal:** update release please config ([e28e87b](https://github.com/orbcorp/orb-csharp/commit/e28e87bb1de4b402ab461226c7d529485bc9f036)) +* **internal:** use `Random.Shared` in newer .NET versions ([5496540](https://github.com/orbcorp/orb-csharp/commit/54965409ef22007f8a76cd1bc6461e5d8892305b)) +* **internal:** use better test examples ([4b03b94](https://github.com/orbcorp/orb-csharp/commit/4b03b94e0f0fe56211981998dd4cfd34fc5b901c)) +* **internal:** use nicer generic names ([6fa9d89](https://github.com/orbcorp/orb-csharp/commit/6fa9d89a900e06c56dc80f1708869ac7d610455d)) +* rename some things ([304c45c](https://github.com/orbcorp/orb-csharp/commit/304c45cc17894d6c769b3c8940b3eaf78016eebf)) +* update formatting ([928b193](https://github.com/orbcorp/orb-csharp/commit/928b1937a8478b46f666d547c8831e8e0971f7f1)) +* use non-aliased `using` ([d670d93](https://github.com/orbcorp/orb-csharp/commit/d670d9359ae682140a6d2972bbde93a516fc27b8)) + + +### Documentation + +* add contributing.md ([f916e97](https://github.com/orbcorp/orb-csharp/commit/f916e97b8e752c2cb63ea4637aaef9faec60d4be)) +* add more comments ([6aaa0c9](https://github.com/orbcorp/orb-csharp/commit/6aaa0c9ae294c17e597f5f0d6e7f023839bed8d3)) +* add more comments ([bb19c13](https://github.com/orbcorp/orb-csharp/commit/bb19c135dd18f639953b7f8a32a84681be71e41e)) +* **client:** document `WithOptions` ([0b988e2](https://github.com/orbcorp/orb-csharp/commit/0b988e27453d9ba28772d77134a9cba0c88e076b)) +* **client:** document max retries ([9284c15](https://github.com/orbcorp/orb-csharp/commit/9284c154a943ee83eef80ea430f09362c3c479f2)) +* **client:** document response validation ([c8458a8](https://github.com/orbcorp/orb-csharp/commit/c8458a87171d596edae06bdd0045367a4d915499)) +* **client:** document timeout option ([64968e6](https://github.com/orbcorp/orb-csharp/commit/64968e6430330b4a1768a8d7b2c05e04bdf1b899)) +* **client:** improve snippet formatting ([6b31ed5](https://github.com/orbcorp/orb-csharp/commit/6b31ed5cc69f52b07ad1cc6bc9a0e3899d7533dd)) +* **client:** separate comment content into paragraphs ([d949333](https://github.com/orbcorp/orb-csharp/commit/d94933349e5ebc1c0b7450d25c0eea8402fdfe5a)) +* **internal:** add warning about implementing interface ([554c0fd](https://github.com/orbcorp/orb-csharp/commit/554c0fd3109b5efc5a7f3d145236308a695c4768)) +* note alpha status ([3167be0](https://github.com/orbcorp/orb-csharp/commit/3167be06e8e3929b18e0d4d6af09f69608e68515)) + + +### Refactors + +* **client:** flatten service namespaces ([3b0a9ab](https://github.com/orbcorp/orb-csharp/commit/3b0a9ab09e0a48da9b1d28deb8a88f3fb3a923be)) +* **client:** improve names of some types ([0531b3c](https://github.com/orbcorp/orb-csharp/commit/0531b3cb47640099a98c50d2a357d7686d1ae613)) +* **client:** make unknown variants implicit ([f9b0119](https://github.com/orbcorp/orb-csharp/commit/f9b01191d06875dbd8d1478c2f74cddfc7906c5a)) +* **client:** move some defaults out of `ClientOptions` ([118fd1e](https://github.com/orbcorp/orb-csharp/commit/118fd1efc79ae60e5869a8774f36028b77deba6f)) +* **client:** pass around `ClientOptions` instead of client ([7ae1ca0](https://github.com/orbcorp/orb-csharp/commit/7ae1ca09baff479f68fa6645fea824c4e375ecd2)) +* **client:** use plural for service namespace ([a4aa7a5](https://github.com/orbcorp/orb-csharp/commit/a4aa7a55fce75601f7d85fdd1c98ea8ff1f9be44)) +* **internal:** remove abstract static methods ([47ee157](https://github.com/orbcorp/orb-csharp/commit/47ee1570eb785f65a95728115311429692c88b40)) +* **internal:** share get/set logic ([af22d1e](https://github.com/orbcorp/orb-csharp/commit/af22d1e5661e63d2fdf0480f34c0b7fcff012966)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..5d381870 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +## Setting up the environment + +To set up the repository, run: + +```sh +$ ./scripts/bootstrap +$ ./scripts/build +``` + +This will install required dependencies and build the SDK. + +## Modifying/Adding code + +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `examples/` directory. + +## Using the repository from source + +To use a local version of this library from source in another project, add it using a directory reference: + +```sh +$ dotnet add reference /path/to/sdk/src/Orb +``` + +## Formatting and linting + +```sh +$ ./scripts/format +$ ./scripts/lint +``` + +## Running tests + +```sh +$ ./scripts/test +``` diff --git a/README.md b/README.md index 98a53c1d..49d2d8fc 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,286 @@ # Orb C# API Library +> [!NOTE] +> The Orb C# API Library is currently in **beta** and we're excited for you to experiment with it! +> +> This library has not yet been exhaustively tested in production environments and may be missing some features you'd expect in a stable release. As we continue development, there may be breaking changes that require updates to your code. +> +> **We'd love your feedback!** Please share any suggestions, bug reports, feature requests, or general thoughts by [filing an issue](https://www.github.com/orbcorp/orb-csharp/issues/new). + The Orb C# SDK provides convenient access to the [Orb REST API](https://docs.withorb.com/reference/api-reference) from applications written in C#. The REST API documentation can be found on [docs.withorb.com](https://docs.withorb.com/reference/api-reference). ## Installation -### Dotnet - ```bash -dotnet add reference /path/to/orb-csharp/src/Orb/ +git clone git@github.com:orbcorp/orb-csharp.git +dotnet add reference orb-csharp/src/Orb ``` +## Requirements + +This library requires .NET Standard 2.0 or later. + ## Usage See the [`examples`](examples) directory for complete and runnable examples. -```C# -using Customers = Orb.Models.Customers; -using Orb = Orb; -using System = System; +```csharp +using System; +using Orb; +using Orb.Models.Customers; -// Configured using the ORB_API_KEY, ORB_WEBHOOK_SECRET and ORB_BASE_URL environment variables -Orb::OrbClient client = new Orb::OrbClient(); +OrbClient client = new(); -var param = new Customers::CustomerCreateParams() +CustomerCreateParams parameters = new() { - Email = "example-customer@withorb.com", Name = "My Customer" + Email = "example-customer@withorb.com", + Name = "My Customer", }; -var customer = await client.Customers.Create(param); +var customer = await client.Customers.Create(parameters); -System::Console.WriteLine(customer); +Console.WriteLine(customer); ``` -## Client Configuration +## Client configuration Configure the client using environment variables: -```C# -using Orb = Orb; +```csharp +using Orb; // Configured using the ORB_API_KEY, ORB_WEBHOOK_SECRET and ORB_BASE_URL environment variables -Orb::OrbClient client = new Orb::OrbClient(); +OrbClient client = new(); ``` Or manually: -```C# -using Orb = Orb; +```csharp +using Orb; + +OrbClient client = new() { APIKey = "My API Key" }; +``` + +Or using a combination of the two approaches. + +See this table for the available options: + +| Property | Environment variable | Required | Default value | +| --------------- | -------------------- | -------- | ------------------------------ | +| `APIKey` | `ORB_API_KEY` | true | - | +| `WebhookSecret` | `ORB_WEBHOOK_SECRET` | false | - | +| `BaseUrl` | `ORB_BASE_URL` | true | `"https://api.withorb.com/v1"` | + +### Modifying configuration + +To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `WithOptions` on any client or service: + +```csharp +using System; + +var customer = await client + .WithOptions(options => + options with + { + BaseUrl = "https://example.com", + Timeout = TimeSpan.FromSeconds(42), + } + ) + .Customers.Create(parameters); + +Console.WriteLine(customer); +``` + +Using a [`with` expression](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression) makes it easy to construct the modified options. + +The `WithOptions` method does not affect the original client or service. + +## Requests and responses + +To send a request to the Orb API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a C# class. + +For example, `client.Customers.Create` should be called with an instance of `CustomerCreateParams`, and it will return an instance of `Task`. + +## Error handling + +The SDK throws custom unchecked exception types: -Orb::OrbClient client = new Orb::OrbClient() +- `OrbApiException`: Base class for API errors. See this table for which exception subclass is thrown for each HTTP status code: + +| Status | Exception | +| ------ | ---------------------------------- | +| 400 | `OrbBadRequestException` | +| 401 | `OrbUnauthorizedException` | +| 403 | `OrbForbiddenException` | +| 404 | `OrbNotFoundException` | +| 422 | `OrbUnprocessableEntityException` | +| 429 | `OrbRateLimitException` | +| 5xx | `Orb5xxException` | +| others | `OrbUnexpectedStatusCodeException` | + +Additionally, all 4xx errors inherit from `Orb4xxException`. + +false + +- `OrbIOException`: I/O networking errors. + +- `OrbInvalidDataException`: Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. + +- `OrbException`: Base class for all exceptions. + +## Pagination + +The SDK defines methods that return a paginated lists of results. It provides convenient ways to access the results either one page at a time or item-by-item across all pages. + +### Auto-pagination + +To iterate through all results across all pages, use the `Paginate` method, which automatically fetches more pages as needed. The method returns an [`IAsyncEnumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.iasyncenumerable-1): + +```csharp +using System; + +var page = await client.Coupons.List(parameters); +await foreach (var item in page.Paginate()) { - APIKey = "My API Key" -}; + Console.WriteLine(item); +} ``` -Alternatively, you can use a combination of the two approaches. +### Manual pagination + +To access individual page items and manually request the next page, use the `Items` property, and `HasNext` and `Next` methods: + +```csharp +using System; + +var page = await client.Coupons.List(); +while (true) +{ + foreach (var item in page.Items) + { + Console.WriteLine(item); + } + if (!page.HasNext()) + { + break; + } + page = await page.Next(); +} +``` + +## Network options + +### Retries + +The SDK automatically retries 2 times by default, with a short exponential backoff between requests. + +Only the following error types are retried: + +- Connection errors (for example, due to a network connectivity problem) +- 408 Request Timeout +- 409 Conflict +- 429 Rate Limit +- 5xx Internal + +The API may also explicitly instruct the SDK to retry or not retry a request. + +To set a custom number of retries, configure the client using the `MaxRetries` method: + +```csharp +using Orb; + +OrbClient client = new() { MaxRetries = 3 }; +``` + +Or configure a single method call using [`WithOptions`](#modifying-configuration): + +```csharp +using System; + +var customer = await client + .WithOptions(options => + options with { MaxRetries = 3 } + ) + .Customers.Create(parameters); + +Console.WriteLine(customer); +``` + +### Timeouts + +Requests time out after 1 minute by default. + +To set a custom timeout, configure the client using the `Timeout` option: + +```csharp +using System; +using Orb; + +OrbClient client = new() { Timeout = TimeSpan.FromSeconds(42) }; +``` + +Or configure a single method call using [`WithOptions`](#modifying-configuration): + +```csharp +using System; + +var customer = await client + .WithOptions(options => + options with { Timeout = TimeSpan.FromSeconds(42) } + ) + .Customers.Create(parameters); + +Console.WriteLine(customer); +``` + +## Undocumented API functionality + +The SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API. + +### Response validation + +In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `string`, but the API could return something else. + +By default, the SDK will not throw an exception in this case. It will throw `OrbInvalidDataException` only if you directly access the property. + +If you would prefer to check that the response is completely well-typed upfront, then either call `Validate`: + +```csharp +var customer = client.Customers.Create(parameters); +customer.Validate(); +``` + +Or configure the client using the `ResponseValidation` option: + +```csharp +using Orb; + +OrbClient client = new() { ResponseValidation = true }; +``` + +Or configure a single method call using [`WithOptions`](#modifying-configuration): + +```csharp +using System; + +var customer = await client + .WithOptions(options => + options with { ResponseValidation = true } + ) + .Customers.Create(parameters); + +Console.WriteLine(customer); +``` + +## Semantic 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 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 that we do not expect to impact the vast majority of users in practice. + +We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. + +We are keen for your feedback; please open an [issue](https://www.github.com/orbcorp/orb-csharp/issues) with questions, bugs, or suggestions. diff --git a/examples/.keep b/examples/.keep new file mode 100644 index 00000000..e69de29b diff --git a/examples/OrbExample/OrbExample.csproj b/examples/OrbExample/OrbExample.csproj index 215e7b03..b166ee76 100644 --- a/examples/OrbExample/OrbExample.csproj +++ b/examples/OrbExample/OrbExample.csproj @@ -1,11 +1,12 @@ - - - - - - Exe - net8.0 - OrbExample - enable - - + + + + + + Exe + net8.0 + OrbExample + enable + disable + + diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..59759611 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,71 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "simple", + "extra-files": [ + { + "type": "xml", + "path": "**/*.csproj", + "xpath": "//Project/PropertyGroup/VersionPrefix", + "glob": true + } + ] +} \ No newline at end of file diff --git a/scripts/lint b/scripts/lint index c7ef3cb9..8c2f26c7 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running dotnet csharpier check" +dotnet csharpier check . + echo "==> Running dotnet format" dotnet format style --severity info --verify-no-changes dotnet format analyzers --severity info --verify-no-changes diff --git a/scripts/mock b/scripts/mock index d2814ae6..0b28f6ea 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & # Wait for server to come online echo -n "Waiting for server" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" fi diff --git a/scripts/test b/scripts/test index a7532729..a562fa22 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! prism_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the prism command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" echo exit 1 diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000..36612f3c --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,34 @@ + + + Orb + Orb + sdk;api;http;library + Apache-2.0 + Copyright 2025 Orb + https://docs.withorb.com/reference/api-reference + https://www.github.com/orbcorp/orb-csharp + git + + + true + + $(NoWarn),1570,1573,1574,1591 + + + true + true + true + embedded + + net8.0;netstandard2.0 + 12 + Debug;Release + true + true + enable + true + disable + + $(NoWarn),0618 + + \ No newline at end of file diff --git a/src/Orb.Tests/Core/FreezableDictionaryTest.cs b/src/Orb.Tests/Core/FreezableDictionaryTest.cs new file mode 100644 index 00000000..d07807ad --- /dev/null +++ b/src/Orb.Tests/Core/FreezableDictionaryTest.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Orb.Core; + +namespace Orb.Tests.Core; + +public class FreezableDictionaryTest : TestBase +{ + [Fact] + public void Unfrozen_Works() + { + var freezable = new FreezableDictionary(); + Assert.Throws(() => freezable["foo"]); + freezable["foo"] = "bar"; + Assert.Equal("bar", freezable["foo"]); + + // overwriting key + freezable["foo"] = "baz"; + Assert.Equal("baz", freezable["foo"]); + + // inserting new key + freezable["bar"] = "foo"; + Assert.Equal("foo", freezable["bar"]); + + Assert.Equal("baz", freezable["foo"]); + } + + [Fact] + public void Frozen_Works() + { + var freezable = new FreezableDictionary() { ["foo"] = "bar" }; + Assert.Equal("bar", freezable.Freeze()["foo"]); + Assert.Equal("bar", freezable["foo"]); + Assert.Throws(() => freezable["bar"]); + Assert.Throws(() => freezable.Freeze()["bar"]); + + // overwriting key + Assert.Throws(() => freezable["foo"] = "baz"); + + // inserting new key + Assert.Throws(() => freezable["baz"] = "buzz"); + } +} diff --git a/src/Orb.Tests/Core/JsonModelTest.cs b/src/Orb.Tests/Core/JsonModelTest.cs new file mode 100644 index 00000000..d6117686 --- /dev/null +++ b/src/Orb.Tests/Core/JsonModelTest.cs @@ -0,0 +1,197 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; + +namespace Orb.Tests.Core; + +public class JsonModelTest +{ + [Fact] + public void GetNotNullClass_WhenPresent_Works() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", "value"); + + var value = JsonModel.GetNotNullClass(dictionary, "key"); + + Assert.Equal("value", value); + } + + [Fact] + public void GetNotNullClass_WhenAbsent_Throws() + { + var dictionary = new Dictionary(); + + var exception = Assert.Throws(() => + JsonModel.GetNotNullClass(dictionary, "key") + ); + + Assert.Equal("'key' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotNullClass_WhenNull_Throws() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", null); + + var exception = Assert.Throws(() => + JsonModel.GetNotNullClass(dictionary, "key") + ); + + Assert.Equal("'key' cannot be null", exception.Message); + } + + [Fact] + public void GetNotNullClass_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", 42); + + var exception = Assert.Throws(() => + JsonModel.GetNotNullClass(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.String", exception.Message); + } + + [Fact] + public void GetNotNullStruct_WhenPresent_Works() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", 42); + + var value = JsonModel.GetNotNullStruct(dictionary, "key"); + + Assert.Equal(42, value); + } + + [Fact] + public void GetNotNullStruct_WhenAbsent_Throws() + { + var dictionary = new Dictionary(); + + var exception = Assert.Throws(() => + JsonModel.GetNotNullStruct(dictionary, "key") + ); + + Assert.Equal("'key' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotNullStruct_WhenNull_Throws() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", null); + + var exception = Assert.Throws(() => + JsonModel.GetNotNullStruct(dictionary, "key") + ); + + Assert.Equal("'key' cannot be null", exception.Message); + } + + [Fact] + public void GetNotNullStruct_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", "value"); + + var exception = Assert.Throws(() => + JsonModel.GetNotNullStruct(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.Int32", exception.Message); + } + + [Fact] + public void GetNullableClass_WhenPresent_Works() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", "value"); + + var value = JsonModel.GetNullableClass(dictionary, "key"); + + Assert.Equal("value", value); + } + + [Fact] + public void GetNullableClass_WhenAbsent_ReturnsNull() + { + var dictionary = new Dictionary(); + + var value = JsonModel.GetNullableClass(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableClass_WhenNull_ReturnsNull() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", null); + + var value = JsonModel.GetNullableClass(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableClass_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", 42); + + var exception = Assert.Throws(() => + JsonModel.GetNullableClass(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.String", exception.Message); + } + + [Fact] + public void GetNullableStruct_WhenPresent_Works() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", 42); + + var value = JsonModel.GetNullableStruct(dictionary, "key"); + + Assert.Equal(42, value); + } + + [Fact] + public void GetNullableStruct_WhenAbsent_ReturnsNull() + { + var dictionary = new Dictionary(); + + var value = JsonModel.GetNullableStruct(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableStruct_WhenNull_ReturnsNull() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", null); + + var value = JsonModel.GetNullableStruct(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableStruct_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + JsonModel.Set(dictionary, "key", "value"); + + var exception = Assert.Throws(() => + JsonModel.GetNullableStruct(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.Int32", exception.Message); + } +} diff --git a/src/Orb.Tests/Core/MultipartJsonModelTest.cs b/src/Orb.Tests/Core/MultipartJsonModelTest.cs new file mode 100644 index 00000000..f6cc24e1 --- /dev/null +++ b/src/Orb.Tests/Core/MultipartJsonModelTest.cs @@ -0,0 +1,196 @@ +using System.Collections.Generic; +using Orb.Core; +using Orb.Exceptions; + +namespace Orb.Tests.Core; + +public class MultipartJsonModelTest +{ + [Fact] + public void GetNotNullClass_WhenPresent_Works() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", "value"); + + var value = MultipartJsonModel.GetNotNullClass(dictionary, "key"); + + Assert.Equal("value", value); + } + + [Fact] + public void GetNotNullClass_WhenAbsent_Throws() + { + var dictionary = new Dictionary(); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNotNullClass(dictionary, "key") + ); + + Assert.Equal("'key' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotNullClass_WhenNull_Throws() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", null); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNotNullClass(dictionary, "key") + ); + + Assert.Equal("'key' cannot be null", exception.Message); + } + + [Fact] + public void GetNotNullClass_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", 42); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNotNullClass(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.String", exception.Message); + } + + [Fact] + public void GetNotNullStruct_WhenPresent_Works() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", 42); + + var value = MultipartJsonModel.GetNotNullStruct(dictionary, "key"); + + Assert.Equal(42, value); + } + + [Fact] + public void GetNotNullStruct_WhenAbsent_Throws() + { + var dictionary = new Dictionary(); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNotNullStruct(dictionary, "key") + ); + + Assert.Equal("'key' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotNullStruct_WhenNull_Throws() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", null); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNotNullStruct(dictionary, "key") + ); + + Assert.Equal("'key' cannot be null", exception.Message); + } + + [Fact] + public void GetNotNullStruct_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", "value"); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNotNullStruct(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.Int32", exception.Message); + } + + [Fact] + public void GetNullableClass_WhenPresent_Works() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", "value"); + + var value = MultipartJsonModel.GetNullableClass(dictionary, "key"); + + Assert.Equal("value", value); + } + + [Fact] + public void GetNullableClass_WhenAbsent_ReturnsNull() + { + var dictionary = new Dictionary(); + + var value = MultipartJsonModel.GetNullableClass(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableClass_WhenNull_ReturnsNull() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", null); + + var value = MultipartJsonModel.GetNullableClass(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableClass_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", 42); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNullableClass(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.String", exception.Message); + } + + [Fact] + public void GetNullableStruct_WhenPresent_Works() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", 42); + + var value = MultipartJsonModel.GetNullableStruct(dictionary, "key"); + + Assert.Equal(42, value); + } + + [Fact] + public void GetNullableStruct_WhenAbsent_ReturnsNull() + { + var dictionary = new Dictionary(); + + var value = MultipartJsonModel.GetNullableStruct(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableStruct_WhenNull_ReturnsNull() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", null); + + var value = MultipartJsonModel.GetNullableStruct(dictionary, "key"); + + Assert.Null(value); + } + + [Fact] + public void GetNullableStruct_WhenMismatchedType_Throws() + { + var dictionary = new Dictionary(); + MultipartJsonModel.Set(dictionary, "key", "value"); + + var exception = Assert.Throws(() => + MultipartJsonModel.GetNullableStruct(dictionary, "key") + ); + + Assert.Equal("'key' must be of type System.Int32", exception.Message); + } +} diff --git a/src/Orb.Tests/Models/AddressTest.cs b/src/Orb.Tests/Models/AddressTest.cs new file mode 100644 index 00000000..71c7c0c7 --- /dev/null +++ b/src/Orb.Tests/Models/AddressTest.cs @@ -0,0 +1,102 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class AddressTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Address + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + string expectedCity = "city"; + string expectedCountry = "country"; + string expectedLine1 = "line1"; + string expectedLine2 = "line2"; + string expectedPostalCode = "postal_code"; + string expectedState = "state"; + + Assert.Equal(expectedCity, model.City); + Assert.Equal(expectedCountry, model.Country); + Assert.Equal(expectedLine1, model.Line1); + Assert.Equal(expectedLine2, model.Line2); + Assert.Equal(expectedPostalCode, model.PostalCode); + Assert.Equal(expectedState, model.State); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Address + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize
(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Address + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize
(element); + Assert.NotNull(deserialized); + + string expectedCity = "city"; + string expectedCountry = "country"; + string expectedLine1 = "line1"; + string expectedLine2 = "line2"; + string expectedPostalCode = "postal_code"; + string expectedState = "state"; + + Assert.Equal(expectedCity, deserialized.City); + Assert.Equal(expectedCountry, deserialized.Country); + Assert.Equal(expectedLine1, deserialized.Line1); + Assert.Equal(expectedLine2, deserialized.Line2); + Assert.Equal(expectedPostalCode, deserialized.PostalCode); + Assert.Equal(expectedState, deserialized.State); + } + + [Fact] + public void Validation_Works() + { + var model = new Address + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/AdjustmentIntervalTest.cs b/src/Orb.Tests/Models/AdjustmentIntervalTest.cs new file mode 100644 index 00000000..319155c6 --- /dev/null +++ b/src/Orb.Tests/Models/AdjustmentIntervalTest.cs @@ -0,0 +1,529 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class AdjustmentIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AdjustmentInterval + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedID = "id"; + Adjustment expectedAdjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + List expectedAppliesToPriceIntervalIDs = ["string"]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + model.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIntervalIDs[i], model.AppliesToPriceIntervalIDs[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AdjustmentInterval + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AdjustmentInterval + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + Adjustment expectedAdjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + List expectedAppliesToPriceIntervalIDs = ["string"]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + deserialized.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal( + expectedAppliesToPriceIntervalIDs[i], + deserialized.AppliesToPriceIntervalIDs[i] + ); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new AdjustmentInterval + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void PlanPhaseUsageDiscountValidationWorks() + { + Adjustment value = new( + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseAmountDiscountValidationWorks() + { + Adjustment value = new( + new PlanPhaseAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhasePercentageDiscountValidationWorks() + { + Adjustment value = new( + new PlanPhasePercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseMinimumValidationWorks() + { + Adjustment value = new( + new PlanPhaseMinimumAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseMaximumValidationWorks() + { + Adjustment value = new( + new PlanPhaseMaximumAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseUsageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseAmountDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new PlanPhaseAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhasePercentageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new PlanPhasePercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseMinimumSerializationRoundtripWorks() + { + Adjustment value = new( + new PlanPhaseMinimumAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseMaximumSerializationRoundtripWorks() + { + Adjustment value = new( + new PlanPhaseMaximumAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/AggregatedCostTest.cs b/src/Orb.Tests/Models/AggregatedCostTest.cs new file mode 100644 index 00000000..4a5a0140 --- /dev/null +++ b/src/Orb.Tests/Models/AggregatedCostTest.cs @@ -0,0 +1,840 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class AggregatedCostTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AggregatedCost + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }; + + List expectedPerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ]; + string expectedSubtotal = "subtotal"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedTotal = "total"; + + Assert.Equal(expectedPerPriceCosts.Count, model.PerPriceCosts.Count); + for (int i = 0; i < expectedPerPriceCosts.Count; i++) + { + Assert.Equal(expectedPerPriceCosts[i], model.PerPriceCosts[i]); + } + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + Assert.Equal(expectedTotal, model.Total); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AggregatedCost + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AggregatedCost + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedPerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ]; + string expectedSubtotal = "subtotal"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedTotal = "total"; + + Assert.Equal(expectedPerPriceCosts.Count, deserialized.PerPriceCosts.Count); + for (int i = 0; i < expectedPerPriceCosts.Count; i++) + { + Assert.Equal(expectedPerPriceCosts[i], deserialized.PerPriceCosts[i]); + } + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + Assert.Equal(expectedTotal, deserialized.Total); + } + + [Fact] + public void Validation_Works() + { + var model = new AggregatedCost + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertCreateForCustomerParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertCreateForCustomerParamsTest.cs new file mode 100644 index 00000000..e4a1f252 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertCreateForCustomerParamsTest.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertCreateForCustomerParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertCreateForCustomerParams + { + CustomerID = "customer_id", + Currency = "currency", + Type = Type.CreditBalanceDepleted, + Thresholds = [new(0)], + }; + + string expectedCustomerID = "customer_id"; + string expectedCurrency = "currency"; + ApiEnum expectedType = Type.CreditBalanceDepleted; + List expectedThresholds = [new(0)]; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedType, parameters.Type); + Assert.NotNull(parameters.Thresholds); + Assert.Equal(expectedThresholds.Count, parameters.Thresholds.Count); + for (int i = 0; i < expectedThresholds.Count; i++) + { + Assert.Equal(expectedThresholds[i], parameters.Thresholds[i]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertCreateForCustomerParams + { + CustomerID = "customer_id", + Currency = "currency", + Type = Type.CreditBalanceDepleted, + }; + + Assert.Null(parameters.Thresholds); + Assert.False(parameters.RawBodyData.ContainsKey("thresholds")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new AlertCreateForCustomerParams + { + CustomerID = "customer_id", + Currency = "currency", + Type = Type.CreditBalanceDepleted, + + Thresholds = null, + }; + + Assert.Null(parameters.Thresholds); + Assert.False(parameters.RawBodyData.ContainsKey("thresholds")); + } +} + +public class TypeTest : TestBase +{ + [Theory] + [InlineData(Type.CreditBalanceDepleted)] + [InlineData(Type.CreditBalanceDropped)] + [InlineData(Type.CreditBalanceRecovered)] + public void Validation_Works(Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Type.CreditBalanceDepleted)] + [InlineData(Type.CreditBalanceDropped)] + [InlineData(Type.CreditBalanceRecovered)] + public void SerializationRoundtrip_Works(Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertCreateForExternalCustomerParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertCreateForExternalCustomerParamsTest.cs new file mode 100644 index 00000000..fb009565 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertCreateForExternalCustomerParamsTest.cs @@ -0,0 +1,130 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertCreateForExternalCustomerParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertCreateForExternalCustomerParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + Type = AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted, + Thresholds = [new(0)], + }; + + string expectedExternalCustomerID = "external_customer_id"; + string expectedCurrency = "currency"; + ApiEnum expectedType = + AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted; + List expectedThresholds = [new(0)]; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedType, parameters.Type); + Assert.NotNull(parameters.Thresholds); + Assert.Equal(expectedThresholds.Count, parameters.Thresholds.Count); + for (int i = 0; i < expectedThresholds.Count; i++) + { + Assert.Equal(expectedThresholds[i], parameters.Thresholds[i]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertCreateForExternalCustomerParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + Type = AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted, + }; + + Assert.Null(parameters.Thresholds); + Assert.False(parameters.RawBodyData.ContainsKey("thresholds")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new AlertCreateForExternalCustomerParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + Type = AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted, + + Thresholds = null, + }; + + Assert.Null(parameters.Thresholds); + Assert.False(parameters.RawBodyData.ContainsKey("thresholds")); + } +} + +public class AlertCreateForExternalCustomerParamsTypeTest : TestBase +{ + [Theory] + [InlineData(AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted)] + [InlineData(AlertCreateForExternalCustomerParamsType.CreditBalanceDropped)] + [InlineData(AlertCreateForExternalCustomerParamsType.CreditBalanceRecovered)] + public void Validation_Works(AlertCreateForExternalCustomerParamsType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted)] + [InlineData(AlertCreateForExternalCustomerParamsType.CreditBalanceDropped)] + [InlineData(AlertCreateForExternalCustomerParamsType.CreditBalanceRecovered)] + public void SerializationRoundtrip_Works(AlertCreateForExternalCustomerParamsType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertCreateForSubscriptionParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertCreateForSubscriptionParamsTest.cs new file mode 100644 index 00000000..9bcd4722 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertCreateForSubscriptionParamsTest.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertCreateForSubscriptionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertCreateForSubscriptionParams + { + SubscriptionID = "subscription_id", + Thresholds = [new(0)], + Type = AlertCreateForSubscriptionParamsType.UsageExceeded, + MetricID = "metric_id", + }; + + string expectedSubscriptionID = "subscription_id"; + List expectedThresholds = [new(0)]; + ApiEnum expectedType = + AlertCreateForSubscriptionParamsType.UsageExceeded; + string expectedMetricID = "metric_id"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedThresholds.Count, parameters.Thresholds.Count); + for (int i = 0; i < expectedThresholds.Count; i++) + { + Assert.Equal(expectedThresholds[i], parameters.Thresholds[i]); + } + Assert.Equal(expectedType, parameters.Type); + Assert.Equal(expectedMetricID, parameters.MetricID); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertCreateForSubscriptionParams + { + SubscriptionID = "subscription_id", + Thresholds = [new(0)], + Type = AlertCreateForSubscriptionParamsType.UsageExceeded, + }; + + Assert.Null(parameters.MetricID); + Assert.False(parameters.RawBodyData.ContainsKey("metric_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new AlertCreateForSubscriptionParams + { + SubscriptionID = "subscription_id", + Thresholds = [new(0)], + Type = AlertCreateForSubscriptionParamsType.UsageExceeded, + + MetricID = null, + }; + + Assert.Null(parameters.MetricID); + Assert.False(parameters.RawBodyData.ContainsKey("metric_id")); + } +} + +public class AlertCreateForSubscriptionParamsTypeTest : TestBase +{ + [Theory] + [InlineData(AlertCreateForSubscriptionParamsType.UsageExceeded)] + [InlineData(AlertCreateForSubscriptionParamsType.CostExceeded)] + public void Validation_Works(AlertCreateForSubscriptionParamsType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AlertCreateForSubscriptionParamsType.UsageExceeded)] + [InlineData(AlertCreateForSubscriptionParamsType.CostExceeded)] + public void SerializationRoundtrip_Works(AlertCreateForSubscriptionParamsType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertDisableParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertDisableParamsTest.cs new file mode 100644 index 00000000..1048dc88 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertDisableParamsTest.cs @@ -0,0 +1,45 @@ +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertDisableParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertDisableParams + { + AlertConfigurationID = "alert_configuration_id", + SubscriptionID = "subscription_id", + }; + + string expectedAlertConfigurationID = "alert_configuration_id"; + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedAlertConfigurationID, parameters.AlertConfigurationID); + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertDisableParams { AlertConfigurationID = "alert_configuration_id" }; + + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new AlertDisableParams + { + AlertConfigurationID = "alert_configuration_id", + + SubscriptionID = null, + }; + + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertEnableParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertEnableParamsTest.cs new file mode 100644 index 00000000..fab000a1 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertEnableParamsTest.cs @@ -0,0 +1,45 @@ +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertEnableParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertEnableParams + { + AlertConfigurationID = "alert_configuration_id", + SubscriptionID = "subscription_id", + }; + + string expectedAlertConfigurationID = "alert_configuration_id"; + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedAlertConfigurationID, parameters.AlertConfigurationID); + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertEnableParams { AlertConfigurationID = "alert_configuration_id" }; + + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new AlertEnableParams + { + AlertConfigurationID = "alert_configuration_id", + + SubscriptionID = null, + }; + + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertListPageResponseTest.cs b/src/Orb.Tests/Models/Alerts/AlertListPageResponseTest.cs new file mode 100644 index 00000000..04984aa9 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertListPageResponseTest.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AlertListPageResponse + { + Data = + [ + new() + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AlertListPageResponse + { + Data = + [ + new() + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AlertListPageResponse + { + Data = + [ + new() + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new AlertListPageResponse + { + Data = + [ + new() + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertListParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertListParamsTest.cs new file mode 100644 index 00000000..f44f5e41 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertListParamsTest.cs @@ -0,0 +1,143 @@ +using System; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + Limit = 1, + SubscriptionID = "subscription_id", + }; + + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + long expectedLimit = 1; + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + SubscriptionID = "subscription_id", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new AlertListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + SubscriptionID = "subscription_id", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new AlertListParams { Limit = 1 }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("external_customer_id")); + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new AlertListParams + { + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Cursor = null, + CustomerID = null, + ExternalCustomerID = null, + SubscriptionID = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("external_customer_id")); + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertRetrieveParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertRetrieveParamsTest.cs new file mode 100644 index 00000000..57b3f030 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertRetrieveParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertRetrieveParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertRetrieveParams { AlertID = "alert_id" }; + + string expectedAlertID = "alert_id"; + + Assert.Equal(expectedAlertID, parameters.AlertID); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertTest.cs b/src/Orb.Tests/Models/Alerts/AlertTest.cs new file mode 100644 index 00000000..915f8b4e --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertTest.cs @@ -0,0 +1,569 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }; + + string expectedID = "XuxCbt7x9L82yyeF"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + bool expectedEnabled = true; + Metric expectedMetric = new("id"); + Plan expectedPlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }; + SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + List expectedThresholds = [new(0)]; + ApiEnum expectedType = AlertType.CreditBalanceDepleted; + List expectedBalanceAlertStatus = + [ + new() { InAlert = true, ThresholdValue = 0 }, + ]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedEnabled, model.Enabled); + Assert.Equal(expectedMetric, model.Metric); + Assert.Equal(expectedPlan, model.Plan); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.NotNull(model.Thresholds); + Assert.Equal(expectedThresholds.Count, model.Thresholds.Count); + for (int i = 0; i < expectedThresholds.Count; i++) + { + Assert.Equal(expectedThresholds[i], model.Thresholds[i]); + } + Assert.Equal(expectedType, model.Type); + Assert.NotNull(model.BalanceAlertStatus); + Assert.Equal(expectedBalanceAlertStatus.Count, model.BalanceAlertStatus.Count); + for (int i = 0; i < expectedBalanceAlertStatus.Count; i++) + { + Assert.Equal(expectedBalanceAlertStatus[i], model.BalanceAlertStatus[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "XuxCbt7x9L82yyeF"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + bool expectedEnabled = true; + Metric expectedMetric = new("id"); + Plan expectedPlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }; + SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + List expectedThresholds = [new(0)]; + ApiEnum expectedType = AlertType.CreditBalanceDepleted; + List expectedBalanceAlertStatus = + [ + new() { InAlert = true, ThresholdValue = 0 }, + ]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedEnabled, deserialized.Enabled); + Assert.Equal(expectedMetric, deserialized.Metric); + Assert.Equal(expectedPlan, deserialized.Plan); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.NotNull(deserialized.Thresholds); + Assert.Equal(expectedThresholds.Count, deserialized.Thresholds.Count); + for (int i = 0; i < expectedThresholds.Count; i++) + { + Assert.Equal(expectedThresholds[i], deserialized.Thresholds[i]); + } + Assert.Equal(expectedType, deserialized.Type); + Assert.NotNull(deserialized.BalanceAlertStatus); + Assert.Equal(expectedBalanceAlertStatus.Count, deserialized.BalanceAlertStatus.Count); + for (int i = 0; i < expectedBalanceAlertStatus.Count; i++) + { + Assert.Equal(expectedBalanceAlertStatus[i], deserialized.BalanceAlertStatus[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + BalanceAlertStatus = [new() { InAlert = true, ThresholdValue = 0 }], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + }; + + Assert.Null(model.BalanceAlertStatus); + Assert.False(model.RawData.ContainsKey("balance_alert_status")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + + BalanceAlertStatus = null, + }; + + Assert.Null(model.BalanceAlertStatus); + Assert.True(model.RawData.ContainsKey("balance_alert_status")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Alert + { + ID = "XuxCbt7x9L82yyeF", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Enabled = true, + Metric = new("id"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }, + Subscription = new("VDGsT23osdLb84KD"), + Thresholds = [new(0)], + Type = AlertType.CreditBalanceDepleted, + + BalanceAlertStatus = null, + }; + + model.Validate(); + } +} + +public class MetricTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Metric { ID = "id" }; + + string expectedID = "id"; + + Assert.Equal(expectedID, model.ID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Metric { ID = "id" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Metric { ID = "id" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + + Assert.Equal(expectedID, deserialized.ID); + } + + [Fact] + public void Validation_Works() + { + var model = new Metric { ID = "id" }; + + model.Validate(); + } +} + +public class PlanTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }; + + string expectedID = "m2t5akQeh2obwxeU"; + string expectedExternalPlanID = "m2t5akQeh2obwxeU"; + string expectedName = "Example plan"; + string expectedPlanVersion = "plan_version"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedExternalPlanID, model.ExternalPlanID); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanVersion, model.PlanVersion); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "m2t5akQeh2obwxeU"; + string expectedExternalPlanID = "m2t5akQeh2obwxeU"; + string expectedName = "Example plan"; + string expectedPlanVersion = "plan_version"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedExternalPlanID, deserialized.ExternalPlanID); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanVersion, deserialized.PlanVersion); + } + + [Fact] + public void Validation_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + PlanVersion = "plan_version", + }; + + model.Validate(); + } +} + +public class AlertTypeTest : TestBase +{ + [Theory] + [InlineData(AlertType.CreditBalanceDepleted)] + [InlineData(AlertType.CreditBalanceDropped)] + [InlineData(AlertType.CreditBalanceRecovered)] + [InlineData(AlertType.UsageExceeded)] + [InlineData(AlertType.CostExceeded)] + public void Validation_Works(AlertType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AlertType.CreditBalanceDepleted)] + [InlineData(AlertType.CreditBalanceDropped)] + [InlineData(AlertType.CreditBalanceRecovered)] + [InlineData(AlertType.UsageExceeded)] + [InlineData(AlertType.CostExceeded)] + public void SerializationRoundtrip_Works(AlertType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BalanceAlertStatusTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BalanceAlertStatus { InAlert = true, ThresholdValue = 0 }; + + bool expectedInAlert = true; + double expectedThresholdValue = 0; + + Assert.Equal(expectedInAlert, model.InAlert); + Assert.Equal(expectedThresholdValue, model.ThresholdValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BalanceAlertStatus { InAlert = true, ThresholdValue = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BalanceAlertStatus { InAlert = true, ThresholdValue = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedInAlert = true; + double expectedThresholdValue = 0; + + Assert.Equal(expectedInAlert, deserialized.InAlert); + Assert.Equal(expectedThresholdValue, deserialized.ThresholdValue); + } + + [Fact] + public void Validation_Works() + { + var model = new BalanceAlertStatus { InAlert = true, ThresholdValue = 0 }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Alerts/AlertUpdateParamsTest.cs b/src/Orb.Tests/Models/Alerts/AlertUpdateParamsTest.cs new file mode 100644 index 00000000..0b87d758 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/AlertUpdateParamsTest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class AlertUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new AlertUpdateParams + { + AlertConfigurationID = "alert_configuration_id", + Thresholds = [new(0)], + }; + + string expectedAlertConfigurationID = "alert_configuration_id"; + List expectedThresholds = [new(0)]; + + Assert.Equal(expectedAlertConfigurationID, parameters.AlertConfigurationID); + Assert.Equal(expectedThresholds.Count, parameters.Thresholds.Count); + for (int i = 0; i < expectedThresholds.Count; i++) + { + Assert.Equal(expectedThresholds[i], parameters.Thresholds[i]); + } + } +} diff --git a/src/Orb.Tests/Models/Alerts/ThresholdTest.cs b/src/Orb.Tests/Models/Alerts/ThresholdTest.cs new file mode 100644 index 00000000..8ab689d2 --- /dev/null +++ b/src/Orb.Tests/Models/Alerts/ThresholdTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models.Alerts; + +namespace Orb.Tests.Models.Alerts; + +public class ThresholdTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Threshold { Value = 0 }; + + double expectedValue = 0; + + Assert.Equal(expectedValue, model.Value); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Threshold { Value = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Threshold { Value = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedValue = 0; + + Assert.Equal(expectedValue, deserialized.Value); + } + + [Fact] + public void Validation_Works() + { + var model = new Threshold { Value = 0 }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/AllocationTest.cs b/src/Orb.Tests/Models/AllocationTest.cs new file mode 100644 index 00000000..d92ece0c --- /dev/null +++ b/src/Orb.Tests/Models/AllocationTest.cs @@ -0,0 +1,451 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class AllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + + bool expectedAllowsRollover = true; + string expectedCurrency = "currency"; + CustomExpiration expectedCustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + List expectedFilters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ]; + + Assert.Equal(expectedAllowsRollover, model.AllowsRollover); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomExpiration, model.CustomExpiration); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedAllowsRollover = true; + string expectedCurrency = "currency"; + CustomExpiration expectedCustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + List expectedFilters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ]; + + Assert.Equal(expectedAllowsRollover, deserialized.AllowsRollover); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomExpiration, deserialized.CustomExpiration); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + }; + + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + + // Null should be interpreted as omitted for these properties + Filters = null, + }; + + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Allocation + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + + // Null should be interpreted as omitted for these properties + Filters = null, + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Filter + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = Field.PriceID; + ApiEnum expectedOperator = Operator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Filter + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Filter + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = Field.PriceID; + ApiEnum expectedOperator = Operator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Filter + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class FieldTest : TestBase +{ + [Theory] + [InlineData(Field.PriceID)] + [InlineData(Field.ItemID)] + [InlineData(Field.PriceType)] + [InlineData(Field.Currency)] + [InlineData(Field.PricingUnitID)] + public void Validation_Works(Field rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Field.PriceID)] + [InlineData(Field.ItemID)] + [InlineData(Field.PriceType)] + [InlineData(Field.Currency)] + [InlineData(Field.PricingUnitID)] + public void SerializationRoundtrip_Works(Field rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class OperatorTest : TestBase +{ + [Theory] + [InlineData(Operator.Includes)] + [InlineData(Operator.Excludes)] + public void Validation_Works(Operator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Operator.Includes)] + [InlineData(Operator.Excludes)] + public void SerializationRoundtrip_Works(Operator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/AmountDiscountIntervalTest.cs b/src/Orb.Tests/Models/AmountDiscountIntervalTest.cs new file mode 100644 index 00000000..8f81eb6f --- /dev/null +++ b/src/Orb.Tests/Models/AmountDiscountIntervalTest.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class AmountDiscountIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AmountDiscountInterval + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedAmountDiscount = "amount_discount"; + List expectedAppliesToPriceIntervalIDs = ["string"]; + ApiEnum expectedDiscountType = + AmountDiscountIntervalDiscountType.Amount; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + model.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIntervalIDs[i], model.AppliesToPriceIntervalIDs[i]); + } + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AmountDiscountInterval + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AmountDiscountInterval + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmountDiscount = "amount_discount"; + List expectedAppliesToPriceIntervalIDs = ["string"]; + ApiEnum expectedDiscountType = + AmountDiscountIntervalDiscountType.Amount; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + deserialized.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal( + expectedAppliesToPriceIntervalIDs[i], + deserialized.AppliesToPriceIntervalIDs[i] + ); + } + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new AmountDiscountInterval + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class AmountDiscountIntervalDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(AmountDiscountIntervalDiscountType.Amount)] + public void Validation_Works(AmountDiscountIntervalDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmountDiscountIntervalDiscountType.Amount)] + public void SerializationRoundtrip_Works(AmountDiscountIntervalDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class AmountDiscountIntervalFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AmountDiscountIntervalFilter + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + AmountDiscountIntervalFilterField.PriceID; + ApiEnum expectedOperator = + AmountDiscountIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AmountDiscountIntervalFilter + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AmountDiscountIntervalFilter + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + AmountDiscountIntervalFilterField.PriceID; + ApiEnum expectedOperator = + AmountDiscountIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AmountDiscountIntervalFilter + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class AmountDiscountIntervalFilterFieldTest : TestBase +{ + [Theory] + [InlineData(AmountDiscountIntervalFilterField.PriceID)] + [InlineData(AmountDiscountIntervalFilterField.ItemID)] + [InlineData(AmountDiscountIntervalFilterField.PriceType)] + [InlineData(AmountDiscountIntervalFilterField.Currency)] + [InlineData(AmountDiscountIntervalFilterField.PricingUnitID)] + public void Validation_Works(AmountDiscountIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmountDiscountIntervalFilterField.PriceID)] + [InlineData(AmountDiscountIntervalFilterField.ItemID)] + [InlineData(AmountDiscountIntervalFilterField.PriceType)] + [InlineData(AmountDiscountIntervalFilterField.Currency)] + [InlineData(AmountDiscountIntervalFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(AmountDiscountIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class AmountDiscountIntervalFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(AmountDiscountIntervalFilterOperator.Includes)] + [InlineData(AmountDiscountIntervalFilterOperator.Excludes)] + public void Validation_Works(AmountDiscountIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmountDiscountIntervalFilterOperator.Includes)] + [InlineData(AmountDiscountIntervalFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(AmountDiscountIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/AmountDiscountTest.cs b/src/Orb.Tests/Models/AmountDiscountTest.cs new file mode 100644 index 00000000..621bc690 --- /dev/null +++ b/src/Orb.Tests/Models/AmountDiscountTest.cs @@ -0,0 +1,493 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class AmountDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string expectedAmountDiscountValue = "amount_discount"; + ApiEnum expectedDiscountType = DiscountType.Amount; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedAmountDiscountValue, model.AmountDiscountValue); + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedReason, model.Reason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmountDiscountValue = "amount_discount"; + ApiEnum expectedDiscountType = DiscountType.Amount; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedAmountDiscountValue, deserialized.AmountDiscountValue); + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedReason, deserialized.Reason); + } + + [Fact] + public void Validation_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new AmountDiscount + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + }; + + model.Validate(); + } +} + +public class DiscountTypeTest : TestBase +{ + [Theory] + [InlineData(DiscountType.Amount)] + public void Validation_Works(DiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DiscountType.Amount)] + public void SerializationRoundtrip_Works(DiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AmountDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AmountDiscountFilter + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + AmountDiscountFilterField.PriceID; + ApiEnum expectedOperator = + AmountDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AmountDiscountFilter + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AmountDiscountFilter + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + AmountDiscountFilterField.PriceID; + ApiEnum expectedOperator = + AmountDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AmountDiscountFilter + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class AmountDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(AmountDiscountFilterField.PriceID)] + [InlineData(AmountDiscountFilterField.ItemID)] + [InlineData(AmountDiscountFilterField.PriceType)] + [InlineData(AmountDiscountFilterField.Currency)] + [InlineData(AmountDiscountFilterField.PricingUnitID)] + public void Validation_Works(AmountDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmountDiscountFilterField.PriceID)] + [InlineData(AmountDiscountFilterField.ItemID)] + [InlineData(AmountDiscountFilterField.PriceType)] + [InlineData(AmountDiscountFilterField.Currency)] + [InlineData(AmountDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(AmountDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AmountDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(AmountDiscountFilterOperator.Includes)] + [InlineData(AmountDiscountFilterOperator.Excludes)] + public void Validation_Works(AmountDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmountDiscountFilterOperator.Includes)] + [InlineData(AmountDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(AmountDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Beta/BetaCreatePlanVersionParamsTest.cs b/src/Orb.Tests/Models/Beta/BetaCreatePlanVersionParamsTest.cs new file mode 100644 index 00000000..e851cd53 --- /dev/null +++ b/src/Orb.Tests/Models/Beta/BetaCreatePlanVersionParamsTest.cs @@ -0,0 +1,19142 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Beta; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Beta; + +public class BetaCreatePlanVersionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BetaCreatePlanVersionParams + { + PlanID = "plan_id", + Version = 0, + AddAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ], + AddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + RemoveAdjustments = [new() { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }], + RemovePrices = [new() { PriceID = "price_id", PlanPhaseOrder = 0 }], + ReplaceAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }, + ], + ReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + SetAsDefault = true, + }; + + string expectedPlanID = "plan_id"; + long expectedVersion = 0; + List expectedAddAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ]; + List expectedAddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ]; + List expectedRemoveAdjustments = + [ + new() { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }, + ]; + List expectedRemovePrices = + [ + new() { PriceID = "price_id", PlanPhaseOrder = 0 }, + ]; + List expectedReplaceAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }, + ]; + List expectedReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ]; + bool expectedSetAsDefault = true; + + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedVersion, parameters.Version); + Assert.NotNull(parameters.AddAdjustments); + Assert.Equal(expectedAddAdjustments.Count, parameters.AddAdjustments.Count); + for (int i = 0; i < expectedAddAdjustments.Count; i++) + { + Assert.Equal(expectedAddAdjustments[i], parameters.AddAdjustments[i]); + } + Assert.NotNull(parameters.AddPrices); + Assert.Equal(expectedAddPrices.Count, parameters.AddPrices.Count); + for (int i = 0; i < expectedAddPrices.Count; i++) + { + Assert.Equal(expectedAddPrices[i], parameters.AddPrices[i]); + } + Assert.NotNull(parameters.RemoveAdjustments); + Assert.Equal(expectedRemoveAdjustments.Count, parameters.RemoveAdjustments.Count); + for (int i = 0; i < expectedRemoveAdjustments.Count; i++) + { + Assert.Equal(expectedRemoveAdjustments[i], parameters.RemoveAdjustments[i]); + } + Assert.NotNull(parameters.RemovePrices); + Assert.Equal(expectedRemovePrices.Count, parameters.RemovePrices.Count); + for (int i = 0; i < expectedRemovePrices.Count; i++) + { + Assert.Equal(expectedRemovePrices[i], parameters.RemovePrices[i]); + } + Assert.NotNull(parameters.ReplaceAdjustments); + Assert.Equal(expectedReplaceAdjustments.Count, parameters.ReplaceAdjustments.Count); + for (int i = 0; i < expectedReplaceAdjustments.Count; i++) + { + Assert.Equal(expectedReplaceAdjustments[i], parameters.ReplaceAdjustments[i]); + } + Assert.NotNull(parameters.ReplacePrices); + Assert.Equal(expectedReplacePrices.Count, parameters.ReplacePrices.Count); + for (int i = 0; i < expectedReplacePrices.Count; i++) + { + Assert.Equal(expectedReplacePrices[i], parameters.ReplacePrices[i]); + } + Assert.Equal(expectedSetAsDefault, parameters.SetAsDefault); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BetaCreatePlanVersionParams { PlanID = "plan_id", Version = 0 }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.SetAsDefault); + Assert.False(parameters.RawBodyData.ContainsKey("set_as_default")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new BetaCreatePlanVersionParams + { + PlanID = "plan_id", + Version = 0, + + AddAdjustments = null, + AddPrices = null, + RemoveAdjustments = null, + RemovePrices = null, + ReplaceAdjustments = null, + ReplacePrices = null, + SetAsDefault = null, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.SetAsDefault); + Assert.False(parameters.RawBodyData.ContainsKey("set_as_default")); + } +} + +public class AddAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + Adjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Adjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Adjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Adjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Adjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Adjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Adjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class AddPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + Price expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPrice, model.Price); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + Price expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPrice, deserialized.Price); + } + + [Fact] + public void Validation_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AddPrice { }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new AddPrice { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new AddPrice + { + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new AddPrice + { + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + model.Validate(); + } +} + +public class PriceTest : TestBase +{ + [Fact] + public void NewPlanUnitValidationWorks() + { + Price value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredValidationWorks() + { + Price value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkValidationWorks() + { + Price value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Price value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageValidationWorks() + { + Price value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixValidationWorks() + { + Price value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanThresholdTotalAmountValidationWorks() + { + Price value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageValidationWorks() + { + Price value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredWithMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageWithAllocationValidationWorks() + { + Price value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithPercentValidationWorks() + { + Price value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithAllocationValidationWorks() + { + Price value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Price value = new( + new TieredWithProration() + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithProrationValidationWorks() + { + Price value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedAllocationValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkWithProrationValidationWorks() + { + Price value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Price value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameValidationWorks() + { + Price value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredPackageValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageValidationWorks() + { + Price value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingValidationWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingValidationWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkValidationWorks() + { + Price value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Price value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMinimumCompositeValidationWorks() + { + Price value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Price value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Price value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Price value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanThresholdTotalAmountSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithPercentSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Price value = new( + new TieredWithProration() + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Price value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMinimumCompositeSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Price value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Price value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + model.Validate(); + } +} + +public class TierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class CadenceTest : TestBase +{ + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void Validation_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void SerializationRoundtrip_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class TieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Custom)] + public void Validation_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class TieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class TieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class PercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void Validation_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void SerializationRoundtrip_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = EventOutputCadence.Annual; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = EventOutputCadence.Annual; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class EventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void Validation_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class EventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class RemoveAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + string expectedAdjustmentID = "adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustmentID, model.AdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAdjustmentID = "adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustmentID, deserialized.AdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id" }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new RemoveAdjustment + { + AdjustmentID = "adjustment_id", + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new RemoveAdjustment + { + AdjustmentID = "adjustment_id", + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class RemovePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + string expectedPriceID = "price_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPriceID = "price_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new RemovePrice { PriceID = "price_id" }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new RemovePrice { PriceID = "price_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new RemovePrice + { + PriceID = "price_id", + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new RemovePrice + { + PriceID = "price_id", + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class ReplaceAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + ReplaceAdjustmentAdjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ReplaceAdjustmentAdjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class ReplaceAdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string expectedReplacesPriceID = "replaces_price_id"; + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + ReplacePricePrice expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPrice, model.Price); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedReplacesPriceID = "replaces_price_id"; + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + ReplacePricePrice expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPrice, deserialized.Price); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePrice { ReplacesPriceID = "replaces_price_id" }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePrice { ReplacesPriceID = "replaces_price_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTest : TestBase +{ + [Fact] + public void NewPlanUnitValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanThresholdTotalAmountValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredWithMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageWithAllocationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithPercentValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithAllocationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceTieredWithProration() + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithProrationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedAllocationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkWithProrationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMinimumCompositeValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePricePercent() + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceEventOutput() + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanThresholdTotalAmountSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredWithMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageWithAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithPercentSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceTieredWithProration() + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithProrationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkWithProrationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMinimumCompositeSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePricePercent() + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceEventOutput() + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + ReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + ReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Annual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Monthly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Quarterly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.OneTime)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Custom)] + public void Validation_Works(ReplacePricePriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Annual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Monthly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Quarterly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.OneTime)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceBulkWithFiltersConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceTieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + ReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + ReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Annual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Monthly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Quarterly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.OneTime)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Custom)] + public void Validation_Works(ReplacePricePriceTieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Annual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Monthly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Quarterly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.OneTime)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePriceTieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(ReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works( + ReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(ReplacePricePriceCumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works( + ReplacePricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + ReplacePricePricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + ReplacePricePricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePricePercentCadence.Annual)] + [InlineData(ReplacePricePricePercentCadence.SemiAnnual)] + [InlineData(ReplacePricePricePercentCadence.Monthly)] + [InlineData(ReplacePricePricePercentCadence.Quarterly)] + [InlineData(ReplacePricePricePercentCadence.OneTime)] + [InlineData(ReplacePricePricePercentCadence.Custom)] + public void Validation_Works(ReplacePricePricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePricePercentCadence.Annual)] + [InlineData(ReplacePricePricePercentCadence.SemiAnnual)] + [InlineData(ReplacePricePricePercentCadence.Monthly)] + [InlineData(ReplacePricePricePercentCadence.Quarterly)] + [InlineData(ReplacePricePricePercentCadence.OneTime)] + [InlineData(ReplacePricePricePercentCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePricePercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class ReplacePricePricePercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceEventOutputCadence.Annual; + ReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceEventOutputCadence.Annual; + ReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceEventOutputCadence.Annual)] + [InlineData(ReplacePricePriceEventOutputCadence.SemiAnnual)] + [InlineData(ReplacePricePriceEventOutputCadence.Monthly)] + [InlineData(ReplacePricePriceEventOutputCadence.Quarterly)] + [InlineData(ReplacePricePriceEventOutputCadence.OneTime)] + [InlineData(ReplacePricePriceEventOutputCadence.Custom)] + public void Validation_Works(ReplacePricePriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceEventOutputCadence.Annual)] + [InlineData(ReplacePricePriceEventOutputCadence.SemiAnnual)] + [InlineData(ReplacePricePriceEventOutputCadence.Monthly)] + [InlineData(ReplacePricePriceEventOutputCadence.Quarterly)] + [InlineData(ReplacePricePriceEventOutputCadence.OneTime)] + [InlineData(ReplacePricePriceEventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceEventOutputEventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceEventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Beta/BetaFetchPlanVersionParamsTest.cs b/src/Orb.Tests/Models/Beta/BetaFetchPlanVersionParamsTest.cs new file mode 100644 index 00000000..f9897ab0 --- /dev/null +++ b/src/Orb.Tests/Models/Beta/BetaFetchPlanVersionParamsTest.cs @@ -0,0 +1,18 @@ +using Orb.Models.Beta; + +namespace Orb.Tests.Models.Beta; + +public class BetaFetchPlanVersionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BetaFetchPlanVersionParams { PlanID = "plan_id", Version = "version" }; + + string expectedPlanID = "plan_id"; + string expectedVersion = "version"; + + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedVersion, parameters.Version); + } +} diff --git a/src/Orb.Tests/Models/Beta/BetaSetDefaultPlanVersionParamsTest.cs b/src/Orb.Tests/Models/Beta/BetaSetDefaultPlanVersionParamsTest.cs new file mode 100644 index 00000000..533cc5c1 --- /dev/null +++ b/src/Orb.Tests/Models/Beta/BetaSetDefaultPlanVersionParamsTest.cs @@ -0,0 +1,18 @@ +using Orb.Models.Beta; + +namespace Orb.Tests.Models.Beta; + +public class BetaSetDefaultPlanVersionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BetaSetDefaultPlanVersionParams { PlanID = "plan_id", Version = 0 }; + + string expectedPlanID = "plan_id"; + long expectedVersion = 0; + + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedVersion, parameters.Version); + } +} diff --git a/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsTest.cs b/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsTest.cs new file mode 100644 index 00000000..839843de --- /dev/null +++ b/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsTest.cs @@ -0,0 +1,19146 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Beta.ExternalPlanID; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Beta.ExternalPlanID; + +public class ExternalPlanIDCreatePlanVersionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPlanIDCreatePlanVersionParams + { + ExternalPlanID = "external_plan_id", + Version = 0, + AddAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ], + AddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + RemoveAdjustments = [new() { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }], + RemovePrices = [new() { PriceID = "price_id", PlanPhaseOrder = 0 }], + ReplaceAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }, + ], + ReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + SetAsDefault = true, + }; + + string expectedExternalPlanID = "external_plan_id"; + long expectedVersion = 0; + List expectedAddAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ]; + List expectedAddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ]; + List expectedRemoveAdjustments = + [ + new() { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }, + ]; + List expectedRemovePrices = + [ + new() { PriceID = "price_id", PlanPhaseOrder = 0 }, + ]; + List expectedReplaceAdjustments = + [ + new() + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }, + ]; + List expectedReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ]; + bool expectedSetAsDefault = true; + + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.Equal(expectedVersion, parameters.Version); + Assert.NotNull(parameters.AddAdjustments); + Assert.Equal(expectedAddAdjustments.Count, parameters.AddAdjustments.Count); + for (int i = 0; i < expectedAddAdjustments.Count; i++) + { + Assert.Equal(expectedAddAdjustments[i], parameters.AddAdjustments[i]); + } + Assert.NotNull(parameters.AddPrices); + Assert.Equal(expectedAddPrices.Count, parameters.AddPrices.Count); + for (int i = 0; i < expectedAddPrices.Count; i++) + { + Assert.Equal(expectedAddPrices[i], parameters.AddPrices[i]); + } + Assert.NotNull(parameters.RemoveAdjustments); + Assert.Equal(expectedRemoveAdjustments.Count, parameters.RemoveAdjustments.Count); + for (int i = 0; i < expectedRemoveAdjustments.Count; i++) + { + Assert.Equal(expectedRemoveAdjustments[i], parameters.RemoveAdjustments[i]); + } + Assert.NotNull(parameters.RemovePrices); + Assert.Equal(expectedRemovePrices.Count, parameters.RemovePrices.Count); + for (int i = 0; i < expectedRemovePrices.Count; i++) + { + Assert.Equal(expectedRemovePrices[i], parameters.RemovePrices[i]); + } + Assert.NotNull(parameters.ReplaceAdjustments); + Assert.Equal(expectedReplaceAdjustments.Count, parameters.ReplaceAdjustments.Count); + for (int i = 0; i < expectedReplaceAdjustments.Count; i++) + { + Assert.Equal(expectedReplaceAdjustments[i], parameters.ReplaceAdjustments[i]); + } + Assert.NotNull(parameters.ReplacePrices); + Assert.Equal(expectedReplacePrices.Count, parameters.ReplacePrices.Count); + for (int i = 0; i < expectedReplacePrices.Count; i++) + { + Assert.Equal(expectedReplacePrices[i], parameters.ReplacePrices[i]); + } + Assert.Equal(expectedSetAsDefault, parameters.SetAsDefault); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ExternalPlanIDCreatePlanVersionParams + { + ExternalPlanID = "external_plan_id", + Version = 0, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.SetAsDefault); + Assert.False(parameters.RawBodyData.ContainsKey("set_as_default")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ExternalPlanIDCreatePlanVersionParams + { + ExternalPlanID = "external_plan_id", + Version = 0, + + AddAdjustments = null, + AddPrices = null, + RemoveAdjustments = null, + RemovePrices = null, + ReplaceAdjustments = null, + ReplacePrices = null, + SetAsDefault = null, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.SetAsDefault); + Assert.False(parameters.RawBodyData.ContainsKey("set_as_default")); + } +} + +public class AddAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + Adjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Adjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new AddAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Adjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Adjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Adjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Adjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Adjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class AddPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + Price expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPrice, model.Price); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + Price expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPrice, deserialized.Price); + } + + [Fact] + public void Validation_Works() + { + var model = new AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AddPrice { }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new AddPrice { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new AddPrice + { + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new AddPrice + { + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + model.Validate(); + } +} + +public class PriceTest : TestBase +{ + [Fact] + public void NewPlanUnitValidationWorks() + { + Price value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredValidationWorks() + { + Price value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkValidationWorks() + { + Price value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Price value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageValidationWorks() + { + Price value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixValidationWorks() + { + Price value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanThresholdTotalAmountValidationWorks() + { + Price value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageValidationWorks() + { + Price value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredWithMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageWithAllocationValidationWorks() + { + Price value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithPercentValidationWorks() + { + Price value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithAllocationValidationWorks() + { + Price value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Price value = new( + new TieredWithProration() + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithProrationValidationWorks() + { + Price value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedAllocationValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkWithProrationValidationWorks() + { + Price value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Price value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameValidationWorks() + { + Price value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredPackageValidationWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageValidationWorks() + { + Price value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingValidationWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingValidationWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkValidationWorks() + { + Price value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Price value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMinimumCompositeValidationWorks() + { + Price value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Price value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Price value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Price value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanThresholdTotalAmountSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithPercentSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Price value = new( + new TieredWithProration() + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Price value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMinimumCompositeSerializationRoundtripWorks() + { + Price value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Price value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Price value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + model.Validate(); + } +} + +public class TierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class CadenceTest : TestBase +{ + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void Validation_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void SerializationRoundtrip_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class TieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Custom)] + public void Validation_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class TieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class TieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class PercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void Validation_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void SerializationRoundtrip_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = EventOutputCadence.Annual; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = EventOutputCadence.Annual; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class EventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void Validation_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class EventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class RemoveAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + string expectedAdjustmentID = "adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustmentID, model.AdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAdjustmentID = "adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustmentID, deserialized.AdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id", PlanPhaseOrder = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id" }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new RemoveAdjustment { AdjustmentID = "adjustment_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new RemoveAdjustment + { + AdjustmentID = "adjustment_id", + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new RemoveAdjustment + { + AdjustmentID = "adjustment_id", + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class RemovePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + string expectedPriceID = "price_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPriceID = "price_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new RemovePrice { PriceID = "price_id", PlanPhaseOrder = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new RemovePrice { PriceID = "price_id" }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new RemovePrice { PriceID = "price_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new RemovePrice + { + PriceID = "price_id", + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new RemovePrice + { + PriceID = "price_id", + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class ReplaceAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + ReplaceAdjustmentAdjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ReplaceAdjustmentAdjustment expectedAdjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + PlanPhaseOrder = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplaceAdjustment + { + Adjustment = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class ReplaceAdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + ReplaceAdjustmentAdjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string expectedReplacesPriceID = "replaces_price_id"; + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + ReplacePricePrice expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPrice, model.Price); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedReplacesPriceID = "replaces_price_id"; + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + ReplacePricePrice expectedPrice = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPrice, deserialized.Price); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + Price = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePrice { ReplacesPriceID = "replaces_price_id" }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePrice { ReplacesPriceID = "replaces_price_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + PlanPhaseOrder = null, + Price = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTest : TestBase +{ + [Fact] + public void NewPlanUnitValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanThresholdTotalAmountValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredWithMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageWithAllocationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithPercentValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithAllocationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceTieredWithProration() + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithProrationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedAllocationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkWithProrationValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMinimumCompositeValidationWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePricePercent() + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceEventOutput() + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanThresholdTotalAmountSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredWithMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageWithAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithPercentSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceTieredWithProration() + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithProrationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkWithProrationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMinimumCompositeSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePricePercent() + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + ReplacePricePrice value = new( + new ReplacePricePriceEventOutput() + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + ReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + ReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Annual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Monthly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Quarterly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.OneTime)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Custom)] + public void Validation_Works(ReplacePricePriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Annual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Monthly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Quarterly)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.OneTime)] + [InlineData(ReplacePricePriceBulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceBulkWithFiltersConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceTieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + ReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + ReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceTieredWithProration + { + Cadence = ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Annual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Monthly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Quarterly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.OneTime)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Custom)] + public void Validation_Works(ReplacePricePriceTieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Annual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Monthly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Quarterly)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.OneTime)] + [InlineData(ReplacePricePriceTieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePriceTieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(ReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works( + ReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(ReplacePricePriceCumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(ReplacePricePriceCumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works( + ReplacePricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + ReplacePricePricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + ReplacePricePricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePricePercent + { + Cadence = ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePricePercentCadence.Annual)] + [InlineData(ReplacePricePricePercentCadence.SemiAnnual)] + [InlineData(ReplacePricePricePercentCadence.Monthly)] + [InlineData(ReplacePricePricePercentCadence.Quarterly)] + [InlineData(ReplacePricePricePercentCadence.OneTime)] + [InlineData(ReplacePricePricePercentCadence.Custom)] + public void Validation_Works(ReplacePricePricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePricePercentCadence.Annual)] + [InlineData(ReplacePricePricePercentCadence.SemiAnnual)] + [InlineData(ReplacePricePricePercentCadence.Monthly)] + [InlineData(ReplacePricePricePercentCadence.Quarterly)] + [InlineData(ReplacePricePricePercentCadence.OneTime)] + [InlineData(ReplacePricePricePercentCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePricePercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePricePercentPercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class ReplacePricePricePercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePricePercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + ReplacePricePriceEventOutputCadence.Annual; + ReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + ReplacePricePriceEventOutputCadence.Annual; + ReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceEventOutput + { + Cadence = ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(ReplacePricePriceEventOutputCadence.Annual)] + [InlineData(ReplacePricePriceEventOutputCadence.SemiAnnual)] + [InlineData(ReplacePricePriceEventOutputCadence.Monthly)] + [InlineData(ReplacePricePriceEventOutputCadence.Quarterly)] + [InlineData(ReplacePricePriceEventOutputCadence.OneTime)] + [InlineData(ReplacePricePriceEventOutputCadence.Custom)] + public void Validation_Works(ReplacePricePriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ReplacePricePriceEventOutputCadence.Annual)] + [InlineData(ReplacePricePriceEventOutputCadence.SemiAnnual)] + [InlineData(ReplacePricePriceEventOutputCadence.Monthly)] + [InlineData(ReplacePricePriceEventOutputCadence.Quarterly)] + [InlineData(ReplacePricePriceEventOutputCadence.OneTime)] + [InlineData(ReplacePricePriceEventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(ReplacePricePriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceEventOutputEventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceEventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ReplacePricePriceEventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParamsTest.cs b/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParamsTest.cs new file mode 100644 index 00000000..56bd6715 --- /dev/null +++ b/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParamsTest.cs @@ -0,0 +1,22 @@ +using Orb.Models.Beta.ExternalPlanID; + +namespace Orb.Tests.Models.Beta.ExternalPlanID; + +public class ExternalPlanIDFetchPlanVersionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPlanIDFetchPlanVersionParams + { + ExternalPlanID = "external_plan_id", + Version = "version", + }; + + string expectedExternalPlanID = "external_plan_id"; + string expectedVersion = "version"; + + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.Equal(expectedVersion, parameters.Version); + } +} diff --git a/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParamsTest.cs b/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParamsTest.cs new file mode 100644 index 00000000..d4d02ff7 --- /dev/null +++ b/src/Orb.Tests/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParamsTest.cs @@ -0,0 +1,22 @@ +using Orb.Models.Beta.ExternalPlanID; + +namespace Orb.Tests.Models.Beta.ExternalPlanID; + +public class ExternalPlanIDSetDefaultPlanVersionParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPlanIDSetDefaultPlanVersionParams + { + ExternalPlanID = "external_plan_id", + Version = 0, + }; + + string expectedExternalPlanID = "external_plan_id"; + long expectedVersion = 0; + + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.Equal(expectedVersion, parameters.Version); + } +} diff --git a/src/Orb.Tests/Models/Beta/PlanVersionPhaseTest.cs b/src/Orb.Tests/Models/Beta/PlanVersionPhaseTest.cs new file mode 100644 index 00000000..692f8c42 --- /dev/null +++ b/src/Orb.Tests/Models/Beta/PlanVersionPhaseTest.cs @@ -0,0 +1,168 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Beta; + +namespace Orb.Tests.Models.Beta; + +public class PlanVersionPhaseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanVersionPhase + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }; + + string expectedID = "id"; + string expectedDescription = "description"; + long expectedDuration = 0; + ApiEnum expectedDurationUnit = DurationUnit.Daily; + string expectedName = "name"; + long expectedOrder = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedDuration, model.Duration); + Assert.Equal(expectedDurationUnit, model.DurationUnit); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedOrder, model.Order); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanVersionPhase + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanVersionPhase + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedDescription = "description"; + long expectedDuration = 0; + ApiEnum expectedDurationUnit = DurationUnit.Daily; + string expectedName = "name"; + long expectedOrder = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedDuration, deserialized.Duration); + Assert.Equal(expectedDurationUnit, deserialized.DurationUnit); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedOrder, deserialized.Order); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanVersionPhase + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }; + + model.Validate(); + } +} + +public class DurationUnitTest : TestBase +{ + [Theory] + [InlineData(DurationUnit.Daily)] + [InlineData(DurationUnit.Monthly)] + [InlineData(DurationUnit.Quarterly)] + [InlineData(DurationUnit.SemiAnnual)] + [InlineData(DurationUnit.Annual)] + public void Validation_Works(DurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DurationUnit.Daily)] + [InlineData(DurationUnit.Monthly)] + [InlineData(DurationUnit.Quarterly)] + [InlineData(DurationUnit.SemiAnnual)] + [InlineData(DurationUnit.Annual)] + public void SerializationRoundtrip_Works(DurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Beta/PlanVersionTest.cs b/src/Orb.Tests/Models/Beta/PlanVersionTest.cs new file mode 100644 index 00000000..78e1d00d --- /dev/null +++ b/src/Orb.Tests/Models/Beta/PlanVersionTest.cs @@ -0,0 +1,1335 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Beta; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Beta; + +public class PlanVersionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanVersion + { + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Version = 0, + }; + + List expectedAdjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }, + ]; + List expectedPrices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ]; + long expectedVersion = 0; + + Assert.Equal(expectedAdjustments.Count, model.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], model.Adjustments[i]); + } + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.NotNull(model.PlanPhases); + Assert.Equal(expectedPlanPhases.Count, model.PlanPhases.Count); + for (int i = 0; i < expectedPlanPhases.Count; i++) + { + Assert.Equal(expectedPlanPhases[i], model.PlanPhases[i]); + } + Assert.Equal(expectedPrices.Count, model.Prices.Count); + for (int i = 0; i < expectedPrices.Count; i++) + { + Assert.Equal(expectedPrices[i], model.Prices[i]); + } + Assert.Equal(expectedVersion, model.Version); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanVersion + { + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Version = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanVersion + { + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Version = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAdjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }, + ]; + List expectedPrices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ]; + long expectedVersion = 0; + + Assert.Equal(expectedAdjustments.Count, deserialized.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], deserialized.Adjustments[i]); + } + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.NotNull(deserialized.PlanPhases); + Assert.Equal(expectedPlanPhases.Count, deserialized.PlanPhases.Count); + for (int i = 0; i < expectedPlanPhases.Count; i++) + { + Assert.Equal(expectedPlanPhases[i], deserialized.PlanPhases[i]); + } + Assert.Equal(expectedPrices.Count, deserialized.Prices.Count); + for (int i = 0; i < expectedPrices.Count; i++) + { + Assert.Equal(expectedPrices[i], deserialized.Prices[i]); + } + Assert.Equal(expectedVersion, deserialized.Version); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanVersion + { + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Duration = 0, + DurationUnit = DurationUnit.Daily, + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Version = 0, + }; + + model.Validate(); + } +} + +public class PlanVersionAdjustmentTest : TestBase +{ + [Fact] + public void PlanPhaseUsageDiscountValidationWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseAmountDiscountValidationWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhasePercentageDiscountValidationWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhasePercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseMinimumValidationWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseMaximumValidationWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseUsageDiscountSerializationRoundtripWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseAmountDiscountSerializationRoundtripWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhasePercentageDiscountSerializationRoundtripWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhasePercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseMinimumSerializationRoundtripWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseMaximumSerializationRoundtripWorks() + { + PlanVersionAdjustment value = new( + new Models::PlanPhaseMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/BillableMetricTinyTest.cs b/src/Orb.Tests/Models/BillableMetricTinyTest.cs new file mode 100644 index 00000000..c06f33ea --- /dev/null +++ b/src/Orb.Tests/Models/BillableMetricTinyTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class BillableMetricTinyTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BillableMetricTiny { ID = "id" }; + + string expectedID = "id"; + + Assert.Equal(expectedID, model.ID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BillableMetricTiny { ID = "id" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BillableMetricTiny { ID = "id" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + + Assert.Equal(expectedID, deserialized.ID); + } + + [Fact] + public void Validation_Works() + { + var model = new BillableMetricTiny { ID = "id" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/BillingCycleAnchorConfigurationTest.cs b/src/Orb.Tests/Models/BillingCycleAnchorConfigurationTest.cs new file mode 100644 index 00000000..78a22350 --- /dev/null +++ b/src/Orb.Tests/Models/BillingCycleAnchorConfigurationTest.cs @@ -0,0 +1,128 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class BillingCycleAnchorConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BillingCycleAnchorConfiguration + { + Day = 1, + Month = 1, + Year = 0, + }; + + long expectedDay = 1; + long expectedMonth = 1; + long expectedYear = 0; + + Assert.Equal(expectedDay, model.Day); + Assert.Equal(expectedMonth, model.Month); + Assert.Equal(expectedYear, model.Year); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BillingCycleAnchorConfiguration + { + Day = 1, + Month = 1, + Year = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BillingCycleAnchorConfiguration + { + Day = 1, + Month = 1, + Year = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedDay = 1; + long expectedMonth = 1; + long expectedYear = 0; + + Assert.Equal(expectedDay, deserialized.Day); + Assert.Equal(expectedMonth, deserialized.Month); + Assert.Equal(expectedYear, deserialized.Year); + } + + [Fact] + public void Validation_Works() + { + var model = new BillingCycleAnchorConfiguration + { + Day = 1, + Month = 1, + Year = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BillingCycleAnchorConfiguration { Day = 1 }; + + Assert.Null(model.Month); + Assert.False(model.RawData.ContainsKey("month")); + Assert.Null(model.Year); + Assert.False(model.RawData.ContainsKey("year")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BillingCycleAnchorConfiguration { Day = 1 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BillingCycleAnchorConfiguration + { + Day = 1, + + Month = null, + Year = null, + }; + + Assert.Null(model.Month); + Assert.True(model.RawData.ContainsKey("month")); + Assert.Null(model.Year); + Assert.True(model.RawData.ContainsKey("year")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BillingCycleAnchorConfiguration + { + Day = 1, + + Month = null, + Year = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/BillingCycleConfigurationTest.cs b/src/Orb.Tests/Models/BillingCycleConfigurationTest.cs new file mode 100644 index 00000000..05108b42 --- /dev/null +++ b/src/Orb.Tests/Models/BillingCycleConfigurationTest.cs @@ -0,0 +1,114 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class BillingCycleConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BillingCycleConfiguration { Duration = 0, DurationUnit = DurationUnit.Day }; + + long expectedDuration = 0; + ApiEnum expectedDurationUnit = DurationUnit.Day; + + Assert.Equal(expectedDuration, model.Duration); + Assert.Equal(expectedDurationUnit, model.DurationUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BillingCycleConfiguration { Duration = 0, DurationUnit = DurationUnit.Day }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BillingCycleConfiguration { Duration = 0, DurationUnit = DurationUnit.Day }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedDuration = 0; + ApiEnum expectedDurationUnit = DurationUnit.Day; + + Assert.Equal(expectedDuration, deserialized.Duration); + Assert.Equal(expectedDurationUnit, deserialized.DurationUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new BillingCycleConfiguration { Duration = 0, DurationUnit = DurationUnit.Day }; + + model.Validate(); + } +} + +public class DurationUnitTest : TestBase +{ + [Theory] + [InlineData(DurationUnit.Day)] + [InlineData(DurationUnit.Month)] + public void Validation_Works(DurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DurationUnit.Day)] + [InlineData(DurationUnit.Month)] + public void SerializationRoundtrip_Works(DurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/BillingCycleRelativeDateTest.cs b/src/Orb.Tests/Models/BillingCycleRelativeDateTest.cs new file mode 100644 index 00000000..fb54c39c --- /dev/null +++ b/src/Orb.Tests/Models/BillingCycleRelativeDateTest.cs @@ -0,0 +1,64 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class BillingCycleRelativeDateTest : TestBase +{ + [Theory] + [InlineData(BillingCycleRelativeDate.StartOfTerm)] + [InlineData(BillingCycleRelativeDate.EndOfTerm)] + public void Validation_Works(BillingCycleRelativeDate rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BillingCycleRelativeDate.StartOfTerm)] + [InlineData(BillingCycleRelativeDate.EndOfTerm)] + public void SerializationRoundtrip_Works(BillingCycleRelativeDate rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/BulkConfigTest.cs b/src/Orb.Tests/Models/BulkConfigTest.cs new file mode 100644 index 00000000..b0302c6a --- /dev/null +++ b/src/Orb.Tests/Models/BulkConfigTest.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class BulkConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkConfig + { + Tiers = [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }], + }; + + List expectedTiers = [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkConfig + { + Tiers = [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkConfig + { + Tiers = [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkConfig + { + Tiers = [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/BulkTierTest.cs b/src/Orb.Tests/Models/BulkTierTest.cs new file mode 100644 index 00000000..1def872d --- /dev/null +++ b/src/Orb.Tests/Models/BulkTierTest.cs @@ -0,0 +1,98 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class BulkTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkTier { UnitAmount = "unit_amount", MaximumUnits = 0 }; + + string expectedUnitAmount = "unit_amount"; + double expectedMaximumUnits = 0; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedMaximumUnits, model.MaximumUnits); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkTier { UnitAmount = "unit_amount", MaximumUnits = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkTier { UnitAmount = "unit_amount", MaximumUnits = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + double expectedMaximumUnits = 0; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedMaximumUnits, deserialized.MaximumUnits); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkTier { UnitAmount = "unit_amount", MaximumUnits = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkTier { UnitAmount = "unit_amount" }; + + Assert.Null(model.MaximumUnits); + Assert.False(model.RawData.ContainsKey("maximum_units")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkTier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkTier + { + UnitAmount = "unit_amount", + + MaximumUnits = null, + }; + + Assert.Null(model.MaximumUnits); + Assert.True(model.RawData.ContainsKey("maximum_units")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkTier + { + UnitAmount = "unit_amount", + + MaximumUnits = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/ChangedSubscriptionResourcesTest.cs b/src/Orb.Tests/Models/ChangedSubscriptionResourcesTest.cs new file mode 100644 index 00000000..e8171109 --- /dev/null +++ b/src/Orb.Tests/Models/ChangedSubscriptionResourcesTest.cs @@ -0,0 +1,9618 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Models = Orb.Models; + +namespace Orb.Tests.Models; + +public class ChangedSubscriptionResourcesTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::ChangedSubscriptionResources + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + List expectedCreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ]; + List expectedCreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + List expectedVoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ]; + List expectedVoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + + Assert.Equal(expectedCreatedCreditNotes.Count, model.CreatedCreditNotes.Count); + for (int i = 0; i < expectedCreatedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreatedCreditNotes[i], model.CreatedCreditNotes[i]); + } + Assert.Equal(expectedCreatedInvoices.Count, model.CreatedInvoices.Count); + for (int i = 0; i < expectedCreatedInvoices.Count; i++) + { + Assert.Equal(expectedCreatedInvoices[i], model.CreatedInvoices[i]); + } + Assert.Equal(expectedVoidedCreditNotes.Count, model.VoidedCreditNotes.Count); + for (int i = 0; i < expectedVoidedCreditNotes.Count; i++) + { + Assert.Equal(expectedVoidedCreditNotes[i], model.VoidedCreditNotes[i]); + } + Assert.Equal(expectedVoidedInvoices.Count, model.VoidedInvoices.Count); + for (int i = 0; i < expectedVoidedInvoices.Count; i++) + { + Assert.Equal(expectedVoidedInvoices[i], model.VoidedInvoices[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::ChangedSubscriptionResources + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::ChangedSubscriptionResources + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedCreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ]; + List expectedCreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + List expectedVoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ]; + List expectedVoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + + Assert.Equal(expectedCreatedCreditNotes.Count, deserialized.CreatedCreditNotes.Count); + for (int i = 0; i < expectedCreatedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreatedCreditNotes[i], deserialized.CreatedCreditNotes[i]); + } + Assert.Equal(expectedCreatedInvoices.Count, deserialized.CreatedInvoices.Count); + for (int i = 0; i < expectedCreatedInvoices.Count; i++) + { + Assert.Equal(expectedCreatedInvoices[i], deserialized.CreatedInvoices[i]); + } + Assert.Equal(expectedVoidedCreditNotes.Count, deserialized.VoidedCreditNotes.Count); + for (int i = 0; i < expectedVoidedCreditNotes.Count; i++) + { + Assert.Equal(expectedVoidedCreditNotes[i], deserialized.VoidedCreditNotes[i]); + } + Assert.Equal(expectedVoidedInvoices.Count, deserialized.VoidedInvoices.Count); + for (int i = 0; i < expectedVoidedInvoices.Count; i++) + { + Assert.Equal(expectedVoidedInvoices[i], deserialized.VoidedInvoices[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Models::ChangedSubscriptionResources + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + model.Validate(); + } +} + +public class CreatedInvoiceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::CreatedInvoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string expectedID = "id"; + string expectedAmountDue = "8.00"; + Models::AutoCollection expectedAutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Models::Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + List expectedCreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ]; + string expectedCurrency = "USD"; + Models::CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + List expectedCustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ]; + Models::CustomerTaxID expectedCustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }; + JsonElement expectedDiscount = JsonSerializer.Deserialize("{}"); + List expectedDiscounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ]; + DateTimeOffset expectedDueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"); + DateTimeOffset expectedEligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedHostedInvoiceURL = "hosted_invoice_url"; + DateTimeOffset expectedInvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"); + string expectedInvoiceNumber = "JYEFHK-00001"; + string expectedInvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + ApiEnum expectedInvoiceSource = + Models::InvoiceSource.Subscription; + bool expectedIsPayableNow = true; + DateTimeOffset expectedIssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedIssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ]; + Models::Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + string expectedMemo = "memo"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Models::Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedPaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ]; + DateTimeOffset expectedPaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedPaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Models::Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + ApiEnum expectedStatus = Models::Status.Issued; + Models::SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + string expectedSubtotal = "8.00"; + DateTimeOffset expectedSyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedTotal = "8.00"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedWillAutoIssue = true; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmountDue, model.AmountDue); + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedBillingAddress, model.BillingAddress); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNotes.Count, model.CreditNotes.Count); + for (int i = 0; i < expectedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreditNotes[i], model.CreditNotes[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal( + expectedCustomerBalanceTransactions.Count, + model.CustomerBalanceTransactions.Count + ); + for (int i = 0; i < expectedCustomerBalanceTransactions.Count; i++) + { + Assert.Equal( + expectedCustomerBalanceTransactions[i], + model.CustomerBalanceTransactions[i] + ); + } + Assert.Equal(expectedCustomerTaxID, model.CustomerTaxID); + Assert.True(JsonElement.DeepEquals(expectedDiscount, model.Discount)); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedDueDate, model.DueDate); + Assert.Equal(expectedEligibleToIssueAt, model.EligibleToIssueAt); + Assert.Equal(expectedHostedInvoiceURL, model.HostedInvoiceURL); + Assert.Equal(expectedInvoiceDate, model.InvoiceDate); + Assert.Equal(expectedInvoiceNumber, model.InvoiceNumber); + Assert.Equal(expectedInvoicePdf, model.InvoicePdf); + Assert.Equal(expectedInvoiceSource, model.InvoiceSource); + Assert.Equal(expectedIsPayableNow, model.IsPayableNow); + Assert.Equal(expectedIssueFailedAt, model.IssueFailedAt); + Assert.Equal(expectedIssuedAt, model.IssuedAt); + Assert.Equal(expectedLineItems.Count, model.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], model.LineItems[i]); + } + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPaidAt, model.PaidAt); + Assert.Equal(expectedPaymentAttempts.Count, model.PaymentAttempts.Count); + for (int i = 0; i < expectedPaymentAttempts.Count; i++) + { + Assert.Equal(expectedPaymentAttempts[i], model.PaymentAttempts[i]); + } + Assert.Equal(expectedPaymentFailedAt, model.PaymentFailedAt); + Assert.Equal(expectedPaymentStartedAt, model.PaymentStartedAt); + Assert.Equal(expectedScheduledIssueAt, model.ScheduledIssueAt); + Assert.Equal(expectedShippingAddress, model.ShippingAddress); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedSyncFailedAt, model.SyncFailedAt); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + Assert.Equal(expectedWillAutoIssue, model.WillAutoIssue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::CreatedInvoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::CreatedInvoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmountDue = "8.00"; + Models::AutoCollection expectedAutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Models::Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + List expectedCreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ]; + string expectedCurrency = "USD"; + Models::CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + List expectedCustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ]; + Models::CustomerTaxID expectedCustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }; + JsonElement expectedDiscount = JsonSerializer.Deserialize("{}"); + List expectedDiscounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ]; + DateTimeOffset expectedDueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"); + DateTimeOffset expectedEligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedHostedInvoiceURL = "hosted_invoice_url"; + DateTimeOffset expectedInvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"); + string expectedInvoiceNumber = "JYEFHK-00001"; + string expectedInvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + ApiEnum expectedInvoiceSource = + Models::InvoiceSource.Subscription; + bool expectedIsPayableNow = true; + DateTimeOffset expectedIssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedIssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ]; + Models::Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + string expectedMemo = "memo"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Models::Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedPaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ]; + DateTimeOffset expectedPaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedPaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Models::Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + ApiEnum expectedStatus = Models::Status.Issued; + Models::SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + string expectedSubtotal = "8.00"; + DateTimeOffset expectedSyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedTotal = "8.00"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedWillAutoIssue = true; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmountDue, deserialized.AmountDue); + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedBillingAddress, deserialized.BillingAddress); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNotes.Count, deserialized.CreditNotes.Count); + for (int i = 0; i < expectedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreditNotes[i], deserialized.CreditNotes[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal( + expectedCustomerBalanceTransactions.Count, + deserialized.CustomerBalanceTransactions.Count + ); + for (int i = 0; i < expectedCustomerBalanceTransactions.Count; i++) + { + Assert.Equal( + expectedCustomerBalanceTransactions[i], + deserialized.CustomerBalanceTransactions[i] + ); + } + Assert.Equal(expectedCustomerTaxID, deserialized.CustomerTaxID); + Assert.True(JsonElement.DeepEquals(expectedDiscount, deserialized.Discount)); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedDueDate, deserialized.DueDate); + Assert.Equal(expectedEligibleToIssueAt, deserialized.EligibleToIssueAt); + Assert.Equal(expectedHostedInvoiceURL, deserialized.HostedInvoiceURL); + Assert.Equal(expectedInvoiceDate, deserialized.InvoiceDate); + Assert.Equal(expectedInvoiceNumber, deserialized.InvoiceNumber); + Assert.Equal(expectedInvoicePdf, deserialized.InvoicePdf); + Assert.Equal(expectedInvoiceSource, deserialized.InvoiceSource); + Assert.Equal(expectedIsPayableNow, deserialized.IsPayableNow); + Assert.Equal(expectedIssueFailedAt, deserialized.IssueFailedAt); + Assert.Equal(expectedIssuedAt, deserialized.IssuedAt); + Assert.Equal(expectedLineItems.Count, deserialized.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], deserialized.LineItems[i]); + } + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPaidAt, deserialized.PaidAt); + Assert.Equal(expectedPaymentAttempts.Count, deserialized.PaymentAttempts.Count); + for (int i = 0; i < expectedPaymentAttempts.Count; i++) + { + Assert.Equal(expectedPaymentAttempts[i], deserialized.PaymentAttempts[i]); + } + Assert.Equal(expectedPaymentFailedAt, deserialized.PaymentFailedAt); + Assert.Equal(expectedPaymentStartedAt, deserialized.PaymentStartedAt); + Assert.Equal(expectedScheduledIssueAt, deserialized.ScheduledIssueAt); + Assert.Equal(expectedShippingAddress, deserialized.ShippingAddress); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedSyncFailedAt, deserialized.SyncFailedAt); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + Assert.Equal(expectedWillAutoIssue, deserialized.WillAutoIssue); + } + + [Fact] + public void Validation_Works() + { + var model = new Models::CreatedInvoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + model.Validate(); + } +} + +public class AutoCollectionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + bool expectedEnabled = true; + DateTimeOffset expectedNextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedNumAttempts = 0; + DateTimeOffset expectedPreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedEnabled, model.Enabled); + Assert.Equal(expectedNextAttemptAt, model.NextAttemptAt); + Assert.Equal(expectedNumAttempts, model.NumAttempts); + Assert.Equal(expectedPreviouslyAttemptedAt, model.PreviouslyAttemptedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedEnabled = true; + DateTimeOffset expectedNextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedNumAttempts = 0; + DateTimeOffset expectedPreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedEnabled, deserialized.Enabled); + Assert.Equal(expectedNextAttemptAt, deserialized.NextAttemptAt); + Assert.Equal(expectedNumAttempts, deserialized.NumAttempts); + Assert.Equal(expectedPreviouslyAttemptedAt, deserialized.PreviouslyAttemptedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new Models::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class CreditNoteTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string expectedID = "id"; + string expectedCreditNoteNumber = "credit_note_number"; + string expectedMemo = "memo"; + string expectedReason = "reason"; + string expectedTotal = "total"; + string expectedType = "type"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreditNoteNumber, model.CreditNoteNumber); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedCreditNoteNumber = "credit_note_number"; + string expectedMemo = "memo"; + string expectedReason = "reason"; + string expectedTotal = "total"; + string expectedType = "type"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreditNoteNumber, deserialized.CreditNoteNumber); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new Models::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + model.Validate(); + } +} + +public class CustomerBalanceTransactionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }; + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = Models::Action.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + Models::CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + Models::InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = Models::Type.Increment; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAction, model.Action); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNote, model.CreditNote); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedInvoice, model.Invoice); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = Models::Action.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + Models::CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + Models::InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = Models::Type.Increment; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAction, deserialized.Action); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNote, deserialized.CreditNote); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedInvoice, deserialized.Invoice); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new Models::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }; + + model.Validate(); + } +} + +public class ActionTest : TestBase +{ + [Theory] + [InlineData(Models::Action.AppliedToInvoice)] + [InlineData(Models::Action.ManualAdjustment)] + [InlineData(Models::Action.ProratedRefund)] + [InlineData(Models::Action.RevertProratedRefund)] + [InlineData(Models::Action.ReturnFromVoiding)] + [InlineData(Models::Action.CreditNoteApplied)] + [InlineData(Models::Action.CreditNoteVoided)] + [InlineData(Models::Action.OverpaymentRefund)] + [InlineData(Models::Action.ExternalPayment)] + [InlineData(Models::Action.SmallInvoiceCarryover)] + public void Validation_Works(Models::Action rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Models::Action.AppliedToInvoice)] + [InlineData(Models::Action.ManualAdjustment)] + [InlineData(Models::Action.ProratedRefund)] + [InlineData(Models::Action.RevertProratedRefund)] + [InlineData(Models::Action.ReturnFromVoiding)] + [InlineData(Models::Action.CreditNoteApplied)] + [InlineData(Models::Action.CreditNoteVoided)] + [InlineData(Models::Action.OverpaymentRefund)] + [InlineData(Models::Action.ExternalPayment)] + [InlineData(Models::Action.SmallInvoiceCarryover)] + public void SerializationRoundtrip_Works(Models::Action rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TypeTest : TestBase +{ + [Theory] + [InlineData(Models::Type.Increment)] + [InlineData(Models::Type.Decrement)] + public void Validation_Works(Models::Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Models::Type.Increment)] + [InlineData(Models::Type.Decrement)] + public void SerializationRoundtrip_Works(Models::Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceSourceTest : TestBase +{ + [Theory] + [InlineData(Models::InvoiceSource.Subscription)] + [InlineData(Models::InvoiceSource.Partial)] + [InlineData(Models::InvoiceSource.OneOff)] + public void Validation_Works(Models::InvoiceSource rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Models::InvoiceSource.Subscription)] + [InlineData(Models::InvoiceSource.Partial)] + [InlineData(Models::InvoiceSource.OneOff)] + public void SerializationRoundtrip_Works(Models::InvoiceSource rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class LineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::LineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Models::Price expectedPrice = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustedSubtotal, model.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, model.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], model.Adjustments[i]); + } + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreditsApplied, model.CreditsApplied); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilter, model.Filter); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, model.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedSubLineItems.Count, model.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], model.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, model.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], model.TaxAmounts[i]); + } + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::LineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::LineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Models::Price expectedPrice = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustedSubtotal, deserialized.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, deserialized.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], deserialized.Adjustments[i]); + } + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreditsApplied, deserialized.CreditsApplied); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, deserialized.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedSubLineItems.Count, deserialized.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], deserialized.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, deserialized.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], deserialized.TaxAmounts[i]); + } + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Models::LineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } +} + +public class LineItemAdjustmentTest : TestBase +{ + [Fact] + public void MonetaryUsageDiscountValidationWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryAmountDiscountValidationWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = Models::AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryPercentageDiscountValidationWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMinimumValidationWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMaximumValidationWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryUsageDiscountSerializationRoundtripWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryAmountDiscountSerializationRoundtripWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = Models::AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryPercentageDiscountSerializationRoundtripWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMinimumSerializationRoundtripWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMaximumSerializationRoundtripWorks() + { + Models::LineItemAdjustment value = new( + new Models::MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class SubLineItemTest : TestBase +{ + [Fact] + public void MatrixValidationWorks() + { + Models::SubLineItem value = new( + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + value.Validate(); + } + + [Fact] + public void TierValidationWorks() + { + Models::SubLineItem value = new( + new Models::TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = Models::TierSubLineItemType.Tier, + } + ); + value.Validate(); + } + + [Fact] + public void OtherValidationWorks() + { + Models::SubLineItem value = new( + new Models::OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = Models::OtherSubLineItemType.Null, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixSerializationRoundtripWorks() + { + Models::SubLineItem value = new( + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TierSerializationRoundtripWorks() + { + Models::SubLineItem value = new( + new Models::TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = Models::TierSubLineItemType.Tier, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void OtherSerializationRoundtripWorks() + { + Models::SubLineItem value = new( + new Models::OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = Models::OtherSubLineItemType.Null, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PaymentAttemptTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Models::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedPaymentProvider = + Models::PaymentProvider.Stripe; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + bool expectedSucceeded = true; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedPaymentProvider, model.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, model.PaymentProviderID); + Assert.Equal(expectedReceiptPdf, model.ReceiptPdf); + Assert.Equal(expectedSucceeded, model.Succeeded); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Models::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Models::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedPaymentProvider = + Models::PaymentProvider.Stripe; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + bool expectedSucceeded = true; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedPaymentProvider, deserialized.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, deserialized.PaymentProviderID); + Assert.Equal(expectedReceiptPdf, deserialized.ReceiptPdf); + Assert.Equal(expectedSucceeded, deserialized.Succeeded); + } + + [Fact] + public void Validation_Works() + { + var model = new Models::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + model.Validate(); + } +} + +public class PaymentProviderTest : TestBase +{ + [Theory] + [InlineData(Models::PaymentProvider.Stripe)] + public void Validation_Works(Models::PaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Models::PaymentProvider.Stripe)] + public void SerializationRoundtrip_Works(Models::PaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Models::Status.Issued)] + [InlineData(Models::Status.Paid)] + [InlineData(Models::Status.Synced)] + [InlineData(Models::Status.Void)] + [InlineData(Models::Status.Draft)] + public void Validation_Works(Models::Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Models::Status.Issued)] + [InlineData(Models::Status.Paid)] + [InlineData(Models::Status.Synced)] + [InlineData(Models::Status.Void)] + [InlineData(Models::Status.Draft)] + public void SerializationRoundtrip_Works(Models::Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/ConversionRateTierTest.cs b/src/Orb.Tests/Models/ConversionRateTierTest.cs new file mode 100644 index 00000000..ffbe79a7 --- /dev/null +++ b/src/Orb.Tests/Models/ConversionRateTierTest.cs @@ -0,0 +1,124 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class ConversionRateTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ConversionRateTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + double expectedFirstUnit = 0; + string expectedUnitAmount = "unit_amount"; + double expectedLastUnit = 0; + + Assert.Equal(expectedFirstUnit, model.FirstUnit); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedLastUnit, model.LastUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ConversionRateTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ConversionRateTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedFirstUnit = 0; + string expectedUnitAmount = "unit_amount"; + double expectedLastUnit = 0; + + Assert.Equal(expectedFirstUnit, deserialized.FirstUnit); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedLastUnit, deserialized.LastUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new ConversionRateTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ConversionRateTier { FirstUnit = 0, UnitAmount = "unit_amount" }; + + Assert.Null(model.LastUnit); + Assert.False(model.RawData.ContainsKey("last_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ConversionRateTier { FirstUnit = 0, UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ConversionRateTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + + LastUnit = null, + }; + + Assert.Null(model.LastUnit); + Assert.True(model.RawData.ContainsKey("last_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ConversionRateTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + + LastUnit = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/ConversionRateTieredConfigTest.cs b/src/Orb.Tests/Models/ConversionRateTieredConfigTest.cs new file mode 100644 index 00000000..bc56f989 --- /dev/null +++ b/src/Orb.Tests/Models/ConversionRateTieredConfigTest.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class ConversionRateTieredConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ConversionRateTieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + }; + + List expectedTiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ConversionRateTieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ConversionRateTieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ConversionRateTieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/ConversionRateUnitConfigTest.cs b/src/Orb.Tests/Models/ConversionRateUnitConfigTest.cs new file mode 100644 index 00000000..f51afe59 --- /dev/null +++ b/src/Orb.Tests/Models/ConversionRateUnitConfigTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class ConversionRateUnitConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ConversionRateUnitConfig { UnitAmount = "unit_amount" }; + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ConversionRateUnitConfig { UnitAmount = "unit_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ConversionRateUnitConfig { UnitAmount = "unit_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ConversionRateUnitConfig { UnitAmount = "unit_amount" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/CouponRedemptionTest.cs b/src/Orb.Tests/Models/CouponRedemptionTest.cs new file mode 100644 index 00000000..3a44ce27 --- /dev/null +++ b/src/Orb.Tests/Models/CouponRedemptionTest.cs @@ -0,0 +1,79 @@ +using System; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class CouponRedemptionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CouponRedemption + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedCouponID = "coupon_id"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCouponID, model.CouponID); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CouponRedemption + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CouponRedemption + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCouponID = "coupon_id"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCouponID, deserialized.CouponID); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new CouponRedemption + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Coupons/CouponArchiveParamsTest.cs b/src/Orb.Tests/Models/Coupons/CouponArchiveParamsTest.cs new file mode 100644 index 00000000..72837063 --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/CouponArchiveParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Coupons; + +namespace Orb.Tests.Models.Coupons; + +public class CouponArchiveParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CouponArchiveParams { CouponID = "coupon_id" }; + + string expectedCouponID = "coupon_id"; + + Assert.Equal(expectedCouponID, parameters.CouponID); + } +} diff --git a/src/Orb.Tests/Models/Coupons/CouponCreateParamsTest.cs b/src/Orb.Tests/Models/Coupons/CouponCreateParamsTest.cs new file mode 100644 index 00000000..94792662 --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/CouponCreateParamsTest.cs @@ -0,0 +1,203 @@ +using System.Text.Json; +using Orb.Models.Coupons; + +namespace Orb.Tests.Models.Coupons; + +public class CouponCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CouponCreateParams + { + Discount = new Percentage(0), + RedemptionCode = "HALFOFF", + DurationInMonths = 12, + MaxRedemptions = 1, + }; + + Discount expectedDiscount = new Percentage(0); + string expectedRedemptionCode = "HALFOFF"; + long expectedDurationInMonths = 12; + long expectedMaxRedemptions = 1; + + Assert.Equal(expectedDiscount, parameters.Discount); + Assert.Equal(expectedRedemptionCode, parameters.RedemptionCode); + Assert.Equal(expectedDurationInMonths, parameters.DurationInMonths); + Assert.Equal(expectedMaxRedemptions, parameters.MaxRedemptions); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CouponCreateParams + { + Discount = new Percentage(0), + RedemptionCode = "HALFOFF", + }; + + Assert.Null(parameters.DurationInMonths); + Assert.False(parameters.RawBodyData.ContainsKey("duration_in_months")); + Assert.Null(parameters.MaxRedemptions); + Assert.False(parameters.RawBodyData.ContainsKey("max_redemptions")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CouponCreateParams + { + Discount = new Percentage(0), + RedemptionCode = "HALFOFF", + + DurationInMonths = null, + MaxRedemptions = null, + }; + + Assert.Null(parameters.DurationInMonths); + Assert.False(parameters.RawBodyData.ContainsKey("duration_in_months")); + Assert.Null(parameters.MaxRedemptions); + Assert.False(parameters.RawBodyData.ContainsKey("max_redemptions")); + } +} + +public class DiscountTest : TestBase +{ + [Fact] + public void PercentageValidationWorks() + { + Discount value = new(new Percentage(0)); + value.Validate(); + } + + [Fact] + public void AmountValidationWorks() + { + Discount value = new(new Amount("amount_discount")); + value.Validate(); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + Discount value = new(new Percentage(0)); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + Discount value = new(new Amount("amount_discount")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PercentageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Percentage { PercentageDiscount = 0 }; + + JsonElement expectedDiscountType = JsonSerializer.Deserialize( + "\"percentage\"" + ); + double expectedPercentageDiscount = 0; + + Assert.True(JsonElement.DeepEquals(expectedDiscountType, model.DiscountType)); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Percentage { PercentageDiscount = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Percentage { PercentageDiscount = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + JsonElement expectedDiscountType = JsonSerializer.Deserialize( + "\"percentage\"" + ); + double expectedPercentageDiscount = 0; + + Assert.True(JsonElement.DeepEquals(expectedDiscountType, deserialized.DiscountType)); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new Percentage { PercentageDiscount = 0 }; + + model.Validate(); + } +} + +public class AmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Amount { AmountDiscount = "amount_discount" }; + + string expectedAmountDiscount = "amount_discount"; + JsonElement expectedDiscountType = JsonSerializer.Deserialize("\"amount\""); + + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.True(JsonElement.DeepEquals(expectedDiscountType, model.DiscountType)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Amount { AmountDiscount = "amount_discount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Amount { AmountDiscount = "amount_discount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmountDiscount = "amount_discount"; + JsonElement expectedDiscountType = JsonSerializer.Deserialize("\"amount\""); + + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.True(JsonElement.DeepEquals(expectedDiscountType, deserialized.DiscountType)); + } + + [Fact] + public void Validation_Works() + { + var model = new Amount { AmountDiscount = "amount_discount" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Coupons/CouponFetchParamsTest.cs b/src/Orb.Tests/Models/Coupons/CouponFetchParamsTest.cs new file mode 100644 index 00000000..f6a3b4e6 --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/CouponFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Coupons; + +namespace Orb.Tests.Models.Coupons; + +public class CouponFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CouponFetchParams { CouponID = "coupon_id" }; + + string expectedCouponID = "coupon_id"; + + Assert.Equal(expectedCouponID, parameters.CouponID); + } +} diff --git a/src/Orb.Tests/Models/Coupons/CouponListPageResponseTest.cs b/src/Orb.Tests/Models/Coupons/CouponListPageResponseTest.cs new file mode 100644 index 00000000..bd0a0ccf --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/CouponListPageResponseTest.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Coupons; + +namespace Orb.Tests.Models.Coupons; + +public class CouponListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CouponListPageResponse + { + Data = + [ + new() + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CouponListPageResponse + { + Data = + [ + new() + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CouponListPageResponse + { + Data = + [ + new() + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new CouponListPageResponse + { + Data = + [ + new() + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Coupons/CouponListParamsTest.cs b/src/Orb.Tests/Models/Coupons/CouponListParamsTest.cs new file mode 100644 index 00000000..f309a826 --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/CouponListParamsTest.cs @@ -0,0 +1,92 @@ +using Orb.Models.Coupons; + +namespace Orb.Tests.Models.Coupons; + +public class CouponListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CouponListParams + { + Cursor = "cursor", + Limit = 1, + RedemptionCode = "redemption_code", + ShowArchived = true, + }; + + string expectedCursor = "cursor"; + long expectedLimit = 1; + string expectedRedemptionCode = "redemption_code"; + bool expectedShowArchived = true; + + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedRedemptionCode, parameters.RedemptionCode); + Assert.Equal(expectedShowArchived, parameters.ShowArchived); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CouponListParams + { + Cursor = "cursor", + RedemptionCode = "redemption_code", + ShowArchived = true, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new CouponListParams + { + Cursor = "cursor", + RedemptionCode = "redemption_code", + ShowArchived = true, + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CouponListParams { Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.RedemptionCode); + Assert.False(parameters.RawQueryData.ContainsKey("redemption_code")); + Assert.Null(parameters.ShowArchived); + Assert.False(parameters.RawQueryData.ContainsKey("show_archived")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CouponListParams + { + Limit = 1, + + Cursor = null, + RedemptionCode = null, + ShowArchived = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.RedemptionCode); + Assert.False(parameters.RawQueryData.ContainsKey("redemption_code")); + Assert.Null(parameters.ShowArchived); + Assert.False(parameters.RawQueryData.ContainsKey("show_archived")); + } +} diff --git a/src/Orb.Tests/Models/Coupons/CouponTest.cs b/src/Orb.Tests/Models/Coupons/CouponTest.cs new file mode 100644 index 00000000..5b3e864a --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/CouponTest.cs @@ -0,0 +1,307 @@ +using System; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Coupons; + +namespace Orb.Tests.Models.Coupons; + +public class CouponTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Coupon + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }; + + string expectedID = "7iz2yanVjQoBZhyH"; + DateTimeOffset expectedArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + CouponDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + long expectedDurationInMonths = 12; + long expectedMaxRedemptions = 0; + string expectedRedemptionCode = "HALFOFF"; + long expectedTimesRedeemed = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedArchivedAt, model.ArchivedAt); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedDurationInMonths, model.DurationInMonths); + Assert.Equal(expectedMaxRedemptions, model.MaxRedemptions); + Assert.Equal(expectedRedemptionCode, model.RedemptionCode); + Assert.Equal(expectedTimesRedeemed, model.TimesRedeemed); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Coupon + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Coupon + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "7iz2yanVjQoBZhyH"; + DateTimeOffset expectedArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + CouponDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + long expectedDurationInMonths = 12; + long expectedMaxRedemptions = 0; + string expectedRedemptionCode = "HALFOFF"; + long expectedTimesRedeemed = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedArchivedAt, deserialized.ArchivedAt); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedDurationInMonths, deserialized.DurationInMonths); + Assert.Equal(expectedMaxRedemptions, deserialized.MaxRedemptions); + Assert.Equal(expectedRedemptionCode, deserialized.RedemptionCode); + Assert.Equal(expectedTimesRedeemed, deserialized.TimesRedeemed); + } + + [Fact] + public void Validation_Works() + { + var model = new Coupon + { + ID = "7iz2yanVjQoBZhyH", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DurationInMonths = 12, + MaxRedemptions = 0, + RedemptionCode = "HALFOFF", + TimesRedeemed = 0, + }; + + model.Validate(); + } +} + +public class CouponDiscountTest : TestBase +{ + [Fact] + public void PercentageValidationWorks() + { + CouponDiscount value = new( + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmountValidationWorks() + { + CouponDiscount value = new( + new AmountDiscount() + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + CouponDiscount value = new( + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + CouponDiscount value = new( + new AmountDiscount() + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Coupons/Subscriptions/SubscriptionListParamsTest.cs b/src/Orb.Tests/Models/Coupons/Subscriptions/SubscriptionListParamsTest.cs new file mode 100644 index 00000000..d7aed28f --- /dev/null +++ b/src/Orb.Tests/Models/Coupons/Subscriptions/SubscriptionListParamsTest.cs @@ -0,0 +1,74 @@ +using Orb.Models.Coupons.Subscriptions; + +namespace Orb.Tests.Models.Coupons.Subscriptions; + +public class SubscriptionListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionListParams + { + CouponID = "coupon_id", + Cursor = "cursor", + Limit = 1, + }; + + string expectedCouponID = "coupon_id"; + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCouponID, parameters.CouponID); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionListParams { CouponID = "coupon_id", Cursor = "cursor" }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new SubscriptionListParams + { + CouponID = "coupon_id", + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionListParams { CouponID = "coupon_id", Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionListParams + { + CouponID = "coupon_id", + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/CreditNoteTinyTest.cs b/src/Orb.Tests/Models/CreditNoteTinyTest.cs new file mode 100644 index 00000000..dbe71b0a --- /dev/null +++ b/src/Orb.Tests/Models/CreditNoteTinyTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class CreditNoteTinyTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditNoteTiny { ID = "id" }; + + string expectedID = "id"; + + Assert.Equal(expectedID, model.ID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditNoteTiny { ID = "id" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditNoteTiny { ID = "id" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + + Assert.Equal(expectedID, deserialized.ID); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditNoteTiny { ID = "id" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/CreditNotes/CreditNoteCreateParamsTest.cs b/src/Orb.Tests/Models/CreditNotes/CreditNoteCreateParamsTest.cs new file mode 100644 index 00000000..ecda3938 --- /dev/null +++ b/src/Orb.Tests/Models/CreditNotes/CreditNoteCreateParamsTest.cs @@ -0,0 +1,309 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.CreditNotes; + +namespace Orb.Tests.Models.CreditNotes; + +public class CreditNoteCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CreditNoteCreateParams + { + LineItems = + [ + new() + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }, + ], + Reason = Reason.Duplicate, + EndDate = "2023-09-22", + Memo = "An optional memo for my credit note.", + StartDate = "2023-09-22", + }; + + List expectedLineItems = + [ + new() + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }, + ]; + ApiEnum expectedReason = Reason.Duplicate; + string expectedEndDate = "2023-09-22"; + string expectedMemo = "An optional memo for my credit note."; + string expectedStartDate = "2023-09-22"; + + Assert.Equal(expectedLineItems.Count, parameters.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], parameters.LineItems[i]); + } + Assert.Equal(expectedReason, parameters.Reason); + Assert.Equal(expectedEndDate, parameters.EndDate); + Assert.Equal(expectedMemo, parameters.Memo); + Assert.Equal(expectedStartDate, parameters.StartDate); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditNoteCreateParams + { + LineItems = + [ + new() + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }, + ], + Reason = Reason.Duplicate, + }; + + Assert.Null(parameters.EndDate); + Assert.False(parameters.RawBodyData.ContainsKey("end_date")); + Assert.Null(parameters.Memo); + Assert.False(parameters.RawBodyData.ContainsKey("memo")); + Assert.Null(parameters.StartDate); + Assert.False(parameters.RawBodyData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CreditNoteCreateParams + { + LineItems = + [ + new() + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }, + ], + Reason = Reason.Duplicate, + + EndDate = null, + Memo = null, + StartDate = null, + }; + + Assert.Null(parameters.EndDate); + Assert.False(parameters.RawBodyData.ContainsKey("end_date")); + Assert.Null(parameters.Memo); + Assert.False(parameters.RawBodyData.ContainsKey("memo")); + Assert.Null(parameters.StartDate); + Assert.False(parameters.RawBodyData.ContainsKey("start_date")); + } +} + +public class LineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LineItem + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }; + + string expectedAmount = "amount"; + string expectedInvoiceLineItemID = "4khy3nwzktxv7"; + string expectedEndDate = "2023-09-22"; + string expectedStartDate = "2023-09-22"; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedInvoiceLineItemID, model.InvoiceLineItemID); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LineItem + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LineItem + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "amount"; + string expectedInvoiceLineItemID = "4khy3nwzktxv7"; + string expectedEndDate = "2023-09-22"; + string expectedStartDate = "2023-09-22"; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedInvoiceLineItemID, deserialized.InvoiceLineItemID); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new LineItem + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LineItem { Amount = "amount", InvoiceLineItemID = "4khy3nwzktxv7" }; + + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LineItem { Amount = "amount", InvoiceLineItemID = "4khy3nwzktxv7" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LineItem + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + + EndDate = null, + StartDate = null, + }; + + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.StartDate); + Assert.True(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LineItem + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + + EndDate = null, + StartDate = null, + }; + + model.Validate(); + } +} + +public class ReasonTest : TestBase +{ + [Theory] + [InlineData(Reason.Duplicate)] + [InlineData(Reason.Fraudulent)] + [InlineData(Reason.OrderChange)] + [InlineData(Reason.ProductUnsatisfactory)] + public void Validation_Works(Reason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Reason.Duplicate)] + [InlineData(Reason.Fraudulent)] + [InlineData(Reason.OrderChange)] + [InlineData(Reason.ProductUnsatisfactory)] + public void SerializationRoundtrip_Works(Reason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/CreditNotes/CreditNoteFetchParamsTest.cs b/src/Orb.Tests/Models/CreditNotes/CreditNoteFetchParamsTest.cs new file mode 100644 index 00000000..c9de4ad2 --- /dev/null +++ b/src/Orb.Tests/Models/CreditNotes/CreditNoteFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.CreditNotes; + +namespace Orb.Tests.Models.CreditNotes; + +public class CreditNoteFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CreditNoteFetchParams { CreditNoteID = "credit_note_id" }; + + string expectedCreditNoteID = "credit_note_id"; + + Assert.Equal(expectedCreditNoteID, parameters.CreditNoteID); + } +} diff --git a/src/Orb.Tests/Models/CreditNotes/CreditNoteListPageResponseTest.cs b/src/Orb.Tests/Models/CreditNotes/CreditNoteListPageResponseTest.cs new file mode 100644 index 00000000..d426c47a --- /dev/null +++ b/src/Orb.Tests/Models/CreditNotes/CreditNoteListPageResponseTest.cs @@ -0,0 +1,527 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.CreditNotes; +using Models = Orb.Models; + +namespace Orb.Tests.Models.CreditNotes; + +public class CreditNoteListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditNoteListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditNoteListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditNoteListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditNoteListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/CreditNotes/CreditNoteListParamsTest.cs b/src/Orb.Tests/Models/CreditNotes/CreditNoteListParamsTest.cs new file mode 100644 index 00000000..5c6b4c1b --- /dev/null +++ b/src/Orb.Tests/Models/CreditNotes/CreditNoteListParamsTest.cs @@ -0,0 +1,113 @@ +using System; +using Orb.Models.CreditNotes; + +namespace Orb.Tests.Models.CreditNotes; + +public class CreditNoteListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CreditNoteListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + Limit = 1, + }; + + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditNoteListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new CreditNoteListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditNoteListParams { Limit = 1 }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CreditNoteListParams + { + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Cursor = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/CustomExpirationTest.cs b/src/Orb.Tests/Models/CustomExpirationTest.cs new file mode 100644 index 00000000..3fe2e13f --- /dev/null +++ b/src/Orb.Tests/Models/CustomExpirationTest.cs @@ -0,0 +1,130 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class CustomExpirationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomExpiration + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + + long expectedDuration = 0; + ApiEnum expectedDurationUnit = + CustomExpirationDurationUnit.Day; + + Assert.Equal(expectedDuration, model.Duration); + Assert.Equal(expectedDurationUnit, model.DurationUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomExpiration + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomExpiration + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedDuration = 0; + ApiEnum expectedDurationUnit = + CustomExpirationDurationUnit.Day; + + Assert.Equal(expectedDuration, deserialized.Duration); + Assert.Equal(expectedDurationUnit, deserialized.DurationUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomExpiration + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + + model.Validate(); + } +} + +public class CustomExpirationDurationUnitTest : TestBase +{ + [Theory] + [InlineData(CustomExpirationDurationUnit.Day)] + [InlineData(CustomExpirationDurationUnit.Month)] + public void Validation_Works(CustomExpirationDurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomExpirationDurationUnit.Day)] + [InlineData(CustomExpirationDurationUnit.Month)] + public void SerializationRoundtrip_Works(CustomExpirationDurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/CustomerMinifiedTest.cs b/src/Orb.Tests/Models/CustomerMinifiedTest.cs new file mode 100644 index 00000000..663b80cd --- /dev/null +++ b/src/Orb.Tests/Models/CustomerMinifiedTest.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class CustomerMinifiedTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerMinified { ID = "id", ExternalCustomerID = "external_customer_id" }; + + string expectedID = "id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedExternalCustomerID, model.ExternalCustomerID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerMinified { ID = "id", ExternalCustomerID = "external_customer_id" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerMinified { ID = "id", ExternalCustomerID = "external_customer_id" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedExternalCustomerID, deserialized.ExternalCustomerID); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerMinified { ID = "id", ExternalCustomerID = "external_customer_id" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/CustomerTaxIDTest.cs b/src/Orb.Tests/Models/CustomerTaxIDTest.cs new file mode 100644 index 00000000..73c59ca3 --- /dev/null +++ b/src/Orb.Tests/Models/CustomerTaxIDTest.cs @@ -0,0 +1,632 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class CustomerTaxIDTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerTaxID + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + + ApiEnum expectedCountry = Country.Ad; + ApiEnum expectedType = CustomerTaxIDType.AdNrt; + string expectedValue = "value"; + + Assert.Equal(expectedCountry, model.Country); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedValue, model.Value); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerTaxID + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerTaxID + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCountry = Country.Ad; + ApiEnum expectedType = CustomerTaxIDType.AdNrt; + string expectedValue = "value"; + + Assert.Equal(expectedCountry, deserialized.Country); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedValue, deserialized.Value); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerTaxID + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + + model.Validate(); + } +} + +public class CountryTest : TestBase +{ + [Theory] + [InlineData(Country.Ad)] + [InlineData(Country.Ae)] + [InlineData(Country.Al)] + [InlineData(Country.Am)] + [InlineData(Country.Ao)] + [InlineData(Country.Ar)] + [InlineData(Country.At)] + [InlineData(Country.Au)] + [InlineData(Country.Aw)] + [InlineData(Country.Az)] + [InlineData(Country.Ba)] + [InlineData(Country.Bb)] + [InlineData(Country.Bd)] + [InlineData(Country.Be)] + [InlineData(Country.Bf)] + [InlineData(Country.Bg)] + [InlineData(Country.Bh)] + [InlineData(Country.Bj)] + [InlineData(Country.Bo)] + [InlineData(Country.Br)] + [InlineData(Country.Bs)] + [InlineData(Country.By)] + [InlineData(Country.Ca)] + [InlineData(Country.Cd)] + [InlineData(Country.Ch)] + [InlineData(Country.Cl)] + [InlineData(Country.Cm)] + [InlineData(Country.Cn)] + [InlineData(Country.Co)] + [InlineData(Country.Cr)] + [InlineData(Country.Cv)] + [InlineData(Country.De)] + [InlineData(Country.Cy)] + [InlineData(Country.Cz)] + [InlineData(Country.Dk)] + [InlineData(Country.Do)] + [InlineData(Country.Ec)] + [InlineData(Country.Ee)] + [InlineData(Country.Eg)] + [InlineData(Country.Es)] + [InlineData(Country.Et)] + [InlineData(Country.Eu)] + [InlineData(Country.Fi)] + [InlineData(Country.Fr)] + [InlineData(Country.GB)] + [InlineData(Country.Ge)] + [InlineData(Country.Gn)] + [InlineData(Country.Gr)] + [InlineData(Country.Hk)] + [InlineData(Country.Hr)] + [InlineData(Country.Hu)] + [InlineData(Country.ID)] + [InlineData(Country.Ie)] + [InlineData(Country.Il)] + [InlineData(Country.In)] + [InlineData(Country.Is)] + [InlineData(Country.It)] + [InlineData(Country.Jp)] + [InlineData(Country.Ke)] + [InlineData(Country.Kg)] + [InlineData(Country.Kh)] + [InlineData(Country.Kr)] + [InlineData(Country.Kz)] + [InlineData(Country.La)] + [InlineData(Country.Li)] + [InlineData(Country.Lt)] + [InlineData(Country.Lu)] + [InlineData(Country.Lv)] + [InlineData(Country.Ma)] + [InlineData(Country.Md)] + [InlineData(Country.Me)] + [InlineData(Country.Mk)] + [InlineData(Country.Mr)] + [InlineData(Country.Mt)] + [InlineData(Country.Mx)] + [InlineData(Country.My)] + [InlineData(Country.Ng)] + [InlineData(Country.Nl)] + [InlineData(Country.No)] + [InlineData(Country.Np)] + [InlineData(Country.Nz)] + [InlineData(Country.Om)] + [InlineData(Country.Pe)] + [InlineData(Country.Ph)] + [InlineData(Country.Pl)] + [InlineData(Country.Pt)] + [InlineData(Country.Ro)] + [InlineData(Country.Rs)] + [InlineData(Country.Ru)] + [InlineData(Country.Sa)] + [InlineData(Country.Se)] + [InlineData(Country.Sg)] + [InlineData(Country.Si)] + [InlineData(Country.Sk)] + [InlineData(Country.Sn)] + [InlineData(Country.Sr)] + [InlineData(Country.Sv)] + [InlineData(Country.Th)] + [InlineData(Country.Tj)] + [InlineData(Country.Tr)] + [InlineData(Country.Tw)] + [InlineData(Country.Tz)] + [InlineData(Country.Ua)] + [InlineData(Country.Ug)] + [InlineData(Country.Us)] + [InlineData(Country.Uy)] + [InlineData(Country.Uz)] + [InlineData(Country.Ve)] + [InlineData(Country.Vn)] + [InlineData(Country.Za)] + [InlineData(Country.Zm)] + [InlineData(Country.Zw)] + public void Validation_Works(Country rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Country.Ad)] + [InlineData(Country.Ae)] + [InlineData(Country.Al)] + [InlineData(Country.Am)] + [InlineData(Country.Ao)] + [InlineData(Country.Ar)] + [InlineData(Country.At)] + [InlineData(Country.Au)] + [InlineData(Country.Aw)] + [InlineData(Country.Az)] + [InlineData(Country.Ba)] + [InlineData(Country.Bb)] + [InlineData(Country.Bd)] + [InlineData(Country.Be)] + [InlineData(Country.Bf)] + [InlineData(Country.Bg)] + [InlineData(Country.Bh)] + [InlineData(Country.Bj)] + [InlineData(Country.Bo)] + [InlineData(Country.Br)] + [InlineData(Country.Bs)] + [InlineData(Country.By)] + [InlineData(Country.Ca)] + [InlineData(Country.Cd)] + [InlineData(Country.Ch)] + [InlineData(Country.Cl)] + [InlineData(Country.Cm)] + [InlineData(Country.Cn)] + [InlineData(Country.Co)] + [InlineData(Country.Cr)] + [InlineData(Country.Cv)] + [InlineData(Country.De)] + [InlineData(Country.Cy)] + [InlineData(Country.Cz)] + [InlineData(Country.Dk)] + [InlineData(Country.Do)] + [InlineData(Country.Ec)] + [InlineData(Country.Ee)] + [InlineData(Country.Eg)] + [InlineData(Country.Es)] + [InlineData(Country.Et)] + [InlineData(Country.Eu)] + [InlineData(Country.Fi)] + [InlineData(Country.Fr)] + [InlineData(Country.GB)] + [InlineData(Country.Ge)] + [InlineData(Country.Gn)] + [InlineData(Country.Gr)] + [InlineData(Country.Hk)] + [InlineData(Country.Hr)] + [InlineData(Country.Hu)] + [InlineData(Country.ID)] + [InlineData(Country.Ie)] + [InlineData(Country.Il)] + [InlineData(Country.In)] + [InlineData(Country.Is)] + [InlineData(Country.It)] + [InlineData(Country.Jp)] + [InlineData(Country.Ke)] + [InlineData(Country.Kg)] + [InlineData(Country.Kh)] + [InlineData(Country.Kr)] + [InlineData(Country.Kz)] + [InlineData(Country.La)] + [InlineData(Country.Li)] + [InlineData(Country.Lt)] + [InlineData(Country.Lu)] + [InlineData(Country.Lv)] + [InlineData(Country.Ma)] + [InlineData(Country.Md)] + [InlineData(Country.Me)] + [InlineData(Country.Mk)] + [InlineData(Country.Mr)] + [InlineData(Country.Mt)] + [InlineData(Country.Mx)] + [InlineData(Country.My)] + [InlineData(Country.Ng)] + [InlineData(Country.Nl)] + [InlineData(Country.No)] + [InlineData(Country.Np)] + [InlineData(Country.Nz)] + [InlineData(Country.Om)] + [InlineData(Country.Pe)] + [InlineData(Country.Ph)] + [InlineData(Country.Pl)] + [InlineData(Country.Pt)] + [InlineData(Country.Ro)] + [InlineData(Country.Rs)] + [InlineData(Country.Ru)] + [InlineData(Country.Sa)] + [InlineData(Country.Se)] + [InlineData(Country.Sg)] + [InlineData(Country.Si)] + [InlineData(Country.Sk)] + [InlineData(Country.Sn)] + [InlineData(Country.Sr)] + [InlineData(Country.Sv)] + [InlineData(Country.Th)] + [InlineData(Country.Tj)] + [InlineData(Country.Tr)] + [InlineData(Country.Tw)] + [InlineData(Country.Tz)] + [InlineData(Country.Ua)] + [InlineData(Country.Ug)] + [InlineData(Country.Us)] + [InlineData(Country.Uy)] + [InlineData(Country.Uz)] + [InlineData(Country.Ve)] + [InlineData(Country.Vn)] + [InlineData(Country.Za)] + [InlineData(Country.Zm)] + [InlineData(Country.Zw)] + public void SerializationRoundtrip_Works(Country rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerTaxIDTypeTest : TestBase +{ + [Theory] + [InlineData(CustomerTaxIDType.AdNrt)] + [InlineData(CustomerTaxIDType.AeTrn)] + [InlineData(CustomerTaxIDType.AlTin)] + [InlineData(CustomerTaxIDType.AmTin)] + [InlineData(CustomerTaxIDType.AoTin)] + [InlineData(CustomerTaxIDType.ArCuit)] + [InlineData(CustomerTaxIDType.EuVat)] + [InlineData(CustomerTaxIDType.AuAbn)] + [InlineData(CustomerTaxIDType.AuArn)] + [InlineData(CustomerTaxIDType.AwTin)] + [InlineData(CustomerTaxIDType.AzTin)] + [InlineData(CustomerTaxIDType.BaTin)] + [InlineData(CustomerTaxIDType.BbTin)] + [InlineData(CustomerTaxIDType.BdBin)] + [InlineData(CustomerTaxIDType.BfIfu)] + [InlineData(CustomerTaxIDType.BgUic)] + [InlineData(CustomerTaxIDType.BhVat)] + [InlineData(CustomerTaxIDType.BjIfu)] + [InlineData(CustomerTaxIDType.BoTin)] + [InlineData(CustomerTaxIDType.BrCnpj)] + [InlineData(CustomerTaxIDType.BrCpf)] + [InlineData(CustomerTaxIDType.BsTin)] + [InlineData(CustomerTaxIDType.ByTin)] + [InlineData(CustomerTaxIDType.CaBn)] + [InlineData(CustomerTaxIDType.CaGstHst)] + [InlineData(CustomerTaxIDType.CaPstBc)] + [InlineData(CustomerTaxIDType.CaPstMB)] + [InlineData(CustomerTaxIDType.CaPstSk)] + [InlineData(CustomerTaxIDType.CaQst)] + [InlineData(CustomerTaxIDType.CdNif)] + [InlineData(CustomerTaxIDType.ChUid)] + [InlineData(CustomerTaxIDType.ChVat)] + [InlineData(CustomerTaxIDType.ClTin)] + [InlineData(CustomerTaxIDType.CmNiu)] + [InlineData(CustomerTaxIDType.CnTin)] + [InlineData(CustomerTaxIDType.CoNit)] + [InlineData(CustomerTaxIDType.CrTin)] + [InlineData(CustomerTaxIDType.CvNif)] + [InlineData(CustomerTaxIDType.DeStn)] + [InlineData(CustomerTaxIDType.DoRcn)] + [InlineData(CustomerTaxIDType.EcRuc)] + [InlineData(CustomerTaxIDType.EgTin)] + [InlineData(CustomerTaxIDType.EsCif)] + [InlineData(CustomerTaxIDType.EtTin)] + [InlineData(CustomerTaxIDType.EuOssVat)] + [InlineData(CustomerTaxIDType.GBVat)] + [InlineData(CustomerTaxIDType.GeVat)] + [InlineData(CustomerTaxIDType.GnNif)] + [InlineData(CustomerTaxIDType.HkBr)] + [InlineData(CustomerTaxIDType.HrOib)] + [InlineData(CustomerTaxIDType.HuTin)] + [InlineData(CustomerTaxIDType.IDNpwp)] + [InlineData(CustomerTaxIDType.IlVat)] + [InlineData(CustomerTaxIDType.InGst)] + [InlineData(CustomerTaxIDType.IsVat)] + [InlineData(CustomerTaxIDType.JpCn)] + [InlineData(CustomerTaxIDType.JpRn)] + [InlineData(CustomerTaxIDType.JpTrn)] + [InlineData(CustomerTaxIDType.KePin)] + [InlineData(CustomerTaxIDType.KgTin)] + [InlineData(CustomerTaxIDType.KhTin)] + [InlineData(CustomerTaxIDType.KrBrn)] + [InlineData(CustomerTaxIDType.KzBin)] + [InlineData(CustomerTaxIDType.LaTin)] + [InlineData(CustomerTaxIDType.LiUid)] + [InlineData(CustomerTaxIDType.LiVat)] + [InlineData(CustomerTaxIDType.MaVat)] + [InlineData(CustomerTaxIDType.MdVat)] + [InlineData(CustomerTaxIDType.MePib)] + [InlineData(CustomerTaxIDType.MkVat)] + [InlineData(CustomerTaxIDType.MrNif)] + [InlineData(CustomerTaxIDType.MxRfc)] + [InlineData(CustomerTaxIDType.MyFrp)] + [InlineData(CustomerTaxIDType.MyItn)] + [InlineData(CustomerTaxIDType.MySst)] + [InlineData(CustomerTaxIDType.NgTin)] + [InlineData(CustomerTaxIDType.NoVat)] + [InlineData(CustomerTaxIDType.NoVoec)] + [InlineData(CustomerTaxIDType.NpPan)] + [InlineData(CustomerTaxIDType.NzGst)] + [InlineData(CustomerTaxIDType.OmVat)] + [InlineData(CustomerTaxIDType.PeRuc)] + [InlineData(CustomerTaxIDType.PhTin)] + [InlineData(CustomerTaxIDType.RoTin)] + [InlineData(CustomerTaxIDType.RsPib)] + [InlineData(CustomerTaxIDType.RuInn)] + [InlineData(CustomerTaxIDType.RuKpp)] + [InlineData(CustomerTaxIDType.SaVat)] + [InlineData(CustomerTaxIDType.SgGst)] + [InlineData(CustomerTaxIDType.SgUen)] + [InlineData(CustomerTaxIDType.SiTin)] + [InlineData(CustomerTaxIDType.SnNinea)] + [InlineData(CustomerTaxIDType.SrFin)] + [InlineData(CustomerTaxIDType.SvNit)] + [InlineData(CustomerTaxIDType.ThVat)] + [InlineData(CustomerTaxIDType.TjTin)] + [InlineData(CustomerTaxIDType.TrTin)] + [InlineData(CustomerTaxIDType.TwVat)] + [InlineData(CustomerTaxIDType.TzVat)] + [InlineData(CustomerTaxIDType.UaVat)] + [InlineData(CustomerTaxIDType.UgTin)] + [InlineData(CustomerTaxIDType.UsEin)] + [InlineData(CustomerTaxIDType.UyRuc)] + [InlineData(CustomerTaxIDType.UzTin)] + [InlineData(CustomerTaxIDType.UzVat)] + [InlineData(CustomerTaxIDType.VeRif)] + [InlineData(CustomerTaxIDType.VnTin)] + [InlineData(CustomerTaxIDType.ZaVat)] + [InlineData(CustomerTaxIDType.ZmTin)] + [InlineData(CustomerTaxIDType.ZwTin)] + public void Validation_Works(CustomerTaxIDType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerTaxIDType.AdNrt)] + [InlineData(CustomerTaxIDType.AeTrn)] + [InlineData(CustomerTaxIDType.AlTin)] + [InlineData(CustomerTaxIDType.AmTin)] + [InlineData(CustomerTaxIDType.AoTin)] + [InlineData(CustomerTaxIDType.ArCuit)] + [InlineData(CustomerTaxIDType.EuVat)] + [InlineData(CustomerTaxIDType.AuAbn)] + [InlineData(CustomerTaxIDType.AuArn)] + [InlineData(CustomerTaxIDType.AwTin)] + [InlineData(CustomerTaxIDType.AzTin)] + [InlineData(CustomerTaxIDType.BaTin)] + [InlineData(CustomerTaxIDType.BbTin)] + [InlineData(CustomerTaxIDType.BdBin)] + [InlineData(CustomerTaxIDType.BfIfu)] + [InlineData(CustomerTaxIDType.BgUic)] + [InlineData(CustomerTaxIDType.BhVat)] + [InlineData(CustomerTaxIDType.BjIfu)] + [InlineData(CustomerTaxIDType.BoTin)] + [InlineData(CustomerTaxIDType.BrCnpj)] + [InlineData(CustomerTaxIDType.BrCpf)] + [InlineData(CustomerTaxIDType.BsTin)] + [InlineData(CustomerTaxIDType.ByTin)] + [InlineData(CustomerTaxIDType.CaBn)] + [InlineData(CustomerTaxIDType.CaGstHst)] + [InlineData(CustomerTaxIDType.CaPstBc)] + [InlineData(CustomerTaxIDType.CaPstMB)] + [InlineData(CustomerTaxIDType.CaPstSk)] + [InlineData(CustomerTaxIDType.CaQst)] + [InlineData(CustomerTaxIDType.CdNif)] + [InlineData(CustomerTaxIDType.ChUid)] + [InlineData(CustomerTaxIDType.ChVat)] + [InlineData(CustomerTaxIDType.ClTin)] + [InlineData(CustomerTaxIDType.CmNiu)] + [InlineData(CustomerTaxIDType.CnTin)] + [InlineData(CustomerTaxIDType.CoNit)] + [InlineData(CustomerTaxIDType.CrTin)] + [InlineData(CustomerTaxIDType.CvNif)] + [InlineData(CustomerTaxIDType.DeStn)] + [InlineData(CustomerTaxIDType.DoRcn)] + [InlineData(CustomerTaxIDType.EcRuc)] + [InlineData(CustomerTaxIDType.EgTin)] + [InlineData(CustomerTaxIDType.EsCif)] + [InlineData(CustomerTaxIDType.EtTin)] + [InlineData(CustomerTaxIDType.EuOssVat)] + [InlineData(CustomerTaxIDType.GBVat)] + [InlineData(CustomerTaxIDType.GeVat)] + [InlineData(CustomerTaxIDType.GnNif)] + [InlineData(CustomerTaxIDType.HkBr)] + [InlineData(CustomerTaxIDType.HrOib)] + [InlineData(CustomerTaxIDType.HuTin)] + [InlineData(CustomerTaxIDType.IDNpwp)] + [InlineData(CustomerTaxIDType.IlVat)] + [InlineData(CustomerTaxIDType.InGst)] + [InlineData(CustomerTaxIDType.IsVat)] + [InlineData(CustomerTaxIDType.JpCn)] + [InlineData(CustomerTaxIDType.JpRn)] + [InlineData(CustomerTaxIDType.JpTrn)] + [InlineData(CustomerTaxIDType.KePin)] + [InlineData(CustomerTaxIDType.KgTin)] + [InlineData(CustomerTaxIDType.KhTin)] + [InlineData(CustomerTaxIDType.KrBrn)] + [InlineData(CustomerTaxIDType.KzBin)] + [InlineData(CustomerTaxIDType.LaTin)] + [InlineData(CustomerTaxIDType.LiUid)] + [InlineData(CustomerTaxIDType.LiVat)] + [InlineData(CustomerTaxIDType.MaVat)] + [InlineData(CustomerTaxIDType.MdVat)] + [InlineData(CustomerTaxIDType.MePib)] + [InlineData(CustomerTaxIDType.MkVat)] + [InlineData(CustomerTaxIDType.MrNif)] + [InlineData(CustomerTaxIDType.MxRfc)] + [InlineData(CustomerTaxIDType.MyFrp)] + [InlineData(CustomerTaxIDType.MyItn)] + [InlineData(CustomerTaxIDType.MySst)] + [InlineData(CustomerTaxIDType.NgTin)] + [InlineData(CustomerTaxIDType.NoVat)] + [InlineData(CustomerTaxIDType.NoVoec)] + [InlineData(CustomerTaxIDType.NpPan)] + [InlineData(CustomerTaxIDType.NzGst)] + [InlineData(CustomerTaxIDType.OmVat)] + [InlineData(CustomerTaxIDType.PeRuc)] + [InlineData(CustomerTaxIDType.PhTin)] + [InlineData(CustomerTaxIDType.RoTin)] + [InlineData(CustomerTaxIDType.RsPib)] + [InlineData(CustomerTaxIDType.RuInn)] + [InlineData(CustomerTaxIDType.RuKpp)] + [InlineData(CustomerTaxIDType.SaVat)] + [InlineData(CustomerTaxIDType.SgGst)] + [InlineData(CustomerTaxIDType.SgUen)] + [InlineData(CustomerTaxIDType.SiTin)] + [InlineData(CustomerTaxIDType.SnNinea)] + [InlineData(CustomerTaxIDType.SrFin)] + [InlineData(CustomerTaxIDType.SvNit)] + [InlineData(CustomerTaxIDType.ThVat)] + [InlineData(CustomerTaxIDType.TjTin)] + [InlineData(CustomerTaxIDType.TrTin)] + [InlineData(CustomerTaxIDType.TwVat)] + [InlineData(CustomerTaxIDType.TzVat)] + [InlineData(CustomerTaxIDType.UaVat)] + [InlineData(CustomerTaxIDType.UgTin)] + [InlineData(CustomerTaxIDType.UsEin)] + [InlineData(CustomerTaxIDType.UyRuc)] + [InlineData(CustomerTaxIDType.UzTin)] + [InlineData(CustomerTaxIDType.UzVat)] + [InlineData(CustomerTaxIDType.VeRif)] + [InlineData(CustomerTaxIDType.VnTin)] + [InlineData(CustomerTaxIDType.ZaVat)] + [InlineData(CustomerTaxIDType.ZmTin)] + [InlineData(CustomerTaxIDType.ZwTin)] + public void SerializationRoundtrip_Works(CustomerTaxIDType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/AccountingProviderConfigTest.cs b/src/Orb.Tests/Models/Customers/AccountingProviderConfigTest.cs new file mode 100644 index 00000000..6b8512a3 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/AccountingProviderConfigTest.cs @@ -0,0 +1,70 @@ +using System.Text.Json; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class AccountingProviderConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AccountingProviderConfig + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }; + + string expectedExternalProviderID = "external_provider_id"; + string expectedProviderType = "provider_type"; + + Assert.Equal(expectedExternalProviderID, model.ExternalProviderID); + Assert.Equal(expectedProviderType, model.ProviderType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AccountingProviderConfig + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AccountingProviderConfig + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedExternalProviderID = "external_provider_id"; + string expectedProviderType = "provider_type"; + + Assert.Equal(expectedExternalProviderID, deserialized.ExternalProviderID); + Assert.Equal(expectedProviderType, deserialized.ProviderType); + } + + [Fact] + public void Validation_Works() + { + var model = new AccountingProviderConfig + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/AddressInputTest.cs b/src/Orb.Tests/Models/Customers/AddressInputTest.cs new file mode 100644 index 00000000..83b3f637 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/AddressInputTest.cs @@ -0,0 +1,172 @@ +using System.Text.Json; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class AddressInputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AddressInput + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + string expectedCity = "city"; + string expectedCountry = "country"; + string expectedLine1 = "line1"; + string expectedLine2 = "line2"; + string expectedPostalCode = "postal_code"; + string expectedState = "state"; + + Assert.Equal(expectedCity, model.City); + Assert.Equal(expectedCountry, model.Country); + Assert.Equal(expectedLine1, model.Line1); + Assert.Equal(expectedLine2, model.Line2); + Assert.Equal(expectedPostalCode, model.PostalCode); + Assert.Equal(expectedState, model.State); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AddressInput + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AddressInput + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCity = "city"; + string expectedCountry = "country"; + string expectedLine1 = "line1"; + string expectedLine2 = "line2"; + string expectedPostalCode = "postal_code"; + string expectedState = "state"; + + Assert.Equal(expectedCity, deserialized.City); + Assert.Equal(expectedCountry, deserialized.Country); + Assert.Equal(expectedLine1, deserialized.Line1); + Assert.Equal(expectedLine2, deserialized.Line2); + Assert.Equal(expectedPostalCode, deserialized.PostalCode); + Assert.Equal(expectedState, deserialized.State); + } + + [Fact] + public void Validation_Works() + { + var model = new AddressInput + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AddressInput { }; + + Assert.Null(model.City); + Assert.False(model.RawData.ContainsKey("city")); + Assert.Null(model.Country); + Assert.False(model.RawData.ContainsKey("country")); + Assert.Null(model.Line1); + Assert.False(model.RawData.ContainsKey("line1")); + Assert.Null(model.Line2); + Assert.False(model.RawData.ContainsKey("line2")); + Assert.Null(model.PostalCode); + Assert.False(model.RawData.ContainsKey("postal_code")); + Assert.Null(model.State); + Assert.False(model.RawData.ContainsKey("state")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new AddressInput { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new AddressInput + { + City = null, + Country = null, + Line1 = null, + Line2 = null, + PostalCode = null, + State = null, + }; + + Assert.Null(model.City); + Assert.True(model.RawData.ContainsKey("city")); + Assert.Null(model.Country); + Assert.True(model.RawData.ContainsKey("country")); + Assert.Null(model.Line1); + Assert.True(model.RawData.ContainsKey("line1")); + Assert.Null(model.Line2); + Assert.True(model.RawData.ContainsKey("line2")); + Assert.Null(model.PostalCode); + Assert.True(model.RawData.ContainsKey("postal_code")); + Assert.Null(model.State); + Assert.True(model.RawData.ContainsKey("state")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new AddressInput + { + City = null, + Country = null, + Line1 = null, + Line2 = null, + PostalCode = null, + State = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionCreateParamsTest.cs b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionCreateParamsTest.cs new file mode 100644 index 00000000..575b5c59 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionCreateParamsTest.cs @@ -0,0 +1,119 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Tests.Models.Customers.BalanceTransactions; + +public class BalanceTransactionCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BalanceTransactionCreateParams + { + CustomerID = "customer_id", + Amount = "amount", + Type = Type.Increment, + Description = "description", + }; + + string expectedCustomerID = "customer_id"; + string expectedAmount = "amount"; + ApiEnum expectedType = Type.Increment; + string expectedDescription = "description"; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedAmount, parameters.Amount); + Assert.Equal(expectedType, parameters.Type); + Assert.Equal(expectedDescription, parameters.Description); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BalanceTransactionCreateParams + { + CustomerID = "customer_id", + Amount = "amount", + Type = Type.Increment, + }; + + Assert.Null(parameters.Description); + Assert.False(parameters.RawBodyData.ContainsKey("description")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new BalanceTransactionCreateParams + { + CustomerID = "customer_id", + Amount = "amount", + Type = Type.Increment, + + Description = null, + }; + + Assert.Null(parameters.Description); + Assert.False(parameters.RawBodyData.ContainsKey("description")); + } +} + +public class TypeTest : TestBase +{ + [Theory] + [InlineData(Type.Increment)] + [InlineData(Type.Decrement)] + public void Validation_Works(Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Type.Increment)] + [InlineData(Type.Decrement)] + public void SerializationRoundtrip_Works(Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseTest.cs b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseTest.cs new file mode 100644 index 00000000..37f6ef0f --- /dev/null +++ b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseTest.cs @@ -0,0 +1,282 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using BalanceTransactions = Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Tests.Models.Customers.BalanceTransactions; + +public class BalanceTransactionCreateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BalanceTransactions::BalanceTransactionCreateResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactions::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactions::BalanceTransactionCreateResponseType.Increment, + }; + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = + BalanceTransactions::Action.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = + BalanceTransactions::BalanceTransactionCreateResponseType.Increment; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAction, model.Action); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNote, model.CreditNote); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedInvoice, model.Invoice); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BalanceTransactions::BalanceTransactionCreateResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactions::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactions::BalanceTransactionCreateResponseType.Increment, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BalanceTransactions::BalanceTransactionCreateResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactions::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactions::BalanceTransactionCreateResponseType.Increment, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = + BalanceTransactions::Action.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = + BalanceTransactions::BalanceTransactionCreateResponseType.Increment; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAction, deserialized.Action); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNote, deserialized.CreditNote); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedInvoice, deserialized.Invoice); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new BalanceTransactions::BalanceTransactionCreateResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactions::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactions::BalanceTransactionCreateResponseType.Increment, + }; + + model.Validate(); + } +} + +public class ActionTest : TestBase +{ + [Theory] + [InlineData(BalanceTransactions::Action.AppliedToInvoice)] + [InlineData(BalanceTransactions::Action.ManualAdjustment)] + [InlineData(BalanceTransactions::Action.ProratedRefund)] + [InlineData(BalanceTransactions::Action.RevertProratedRefund)] + [InlineData(BalanceTransactions::Action.ReturnFromVoiding)] + [InlineData(BalanceTransactions::Action.CreditNoteApplied)] + [InlineData(BalanceTransactions::Action.CreditNoteVoided)] + [InlineData(BalanceTransactions::Action.OverpaymentRefund)] + [InlineData(BalanceTransactions::Action.ExternalPayment)] + [InlineData(BalanceTransactions::Action.SmallInvoiceCarryover)] + public void Validation_Works(BalanceTransactions::Action rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BalanceTransactions::Action.AppliedToInvoice)] + [InlineData(BalanceTransactions::Action.ManualAdjustment)] + [InlineData(BalanceTransactions::Action.ProratedRefund)] + [InlineData(BalanceTransactions::Action.RevertProratedRefund)] + [InlineData(BalanceTransactions::Action.ReturnFromVoiding)] + [InlineData(BalanceTransactions::Action.CreditNoteApplied)] + [InlineData(BalanceTransactions::Action.CreditNoteVoided)] + [InlineData(BalanceTransactions::Action.OverpaymentRefund)] + [InlineData(BalanceTransactions::Action.ExternalPayment)] + [InlineData(BalanceTransactions::Action.SmallInvoiceCarryover)] + public void SerializationRoundtrip_Works(BalanceTransactions::Action rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BalanceTransactionCreateResponseTypeTest : TestBase +{ + [Theory] + [InlineData(BalanceTransactions::BalanceTransactionCreateResponseType.Increment)] + [InlineData(BalanceTransactions::BalanceTransactionCreateResponseType.Decrement)] + public void Validation_Works(BalanceTransactions::BalanceTransactionCreateResponseType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BalanceTransactions::BalanceTransactionCreateResponseType.Increment)] + [InlineData(BalanceTransactions::BalanceTransactionCreateResponseType.Decrement)] + public void SerializationRoundtrip_Works( + BalanceTransactions::BalanceTransactionCreateResponseType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseTest.cs b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseTest.cs new file mode 100644 index 00000000..12dbaf92 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseTest.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Tests.Models.Customers.BalanceTransactions; + +public class BalanceTransactionListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BalanceTransactionListPageResponse + { + Data = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BalanceTransactionListPageResponse + { + Data = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BalanceTransactionListPageResponse + { + Data = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new BalanceTransactionListPageResponse + { + Data = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListParamsTest.cs b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListParamsTest.cs new file mode 100644 index 00000000..b8407cdc --- /dev/null +++ b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListParamsTest.cs @@ -0,0 +1,119 @@ +using System; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Tests.Models.Customers.BalanceTransactions; + +public class BalanceTransactionListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BalanceTransactionListParams + { + CustomerID = "customer_id", + Cursor = "cursor", + Limit = 1, + OperationTimeGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedCustomerID = "customer_id"; + string expectedCursor = "cursor"; + long expectedLimit = 1; + DateTimeOffset expectedOperationTimeGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedOperationTimeGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedOperationTimeLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedOperationTimeLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedOperationTimeGt, parameters.OperationTimeGt); + Assert.Equal(expectedOperationTimeGte, parameters.OperationTimeGte); + Assert.Equal(expectedOperationTimeLt, parameters.OperationTimeLt); + Assert.Equal(expectedOperationTimeLte, parameters.OperationTimeLte); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BalanceTransactionListParams + { + CustomerID = "customer_id", + Cursor = "cursor", + OperationTimeGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new BalanceTransactionListParams + { + CustomerID = "customer_id", + Cursor = "cursor", + OperationTimeGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + OperationTimeLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BalanceTransactionListParams { CustomerID = "customer_id", Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.OperationTimeGt); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[gt]")); + Assert.Null(parameters.OperationTimeGte); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[gte]")); + Assert.Null(parameters.OperationTimeLt); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[lt]")); + Assert.Null(parameters.OperationTimeLte); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[lte]")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new BalanceTransactionListParams + { + CustomerID = "customer_id", + Limit = 1, + + Cursor = null, + OperationTimeGt = null, + OperationTimeGte = null, + OperationTimeLt = null, + OperationTimeLte = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.OperationTimeGt); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[gt]")); + Assert.Null(parameters.OperationTimeGte); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[gte]")); + Assert.Null(parameters.OperationTimeLt); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[lt]")); + Assert.Null(parameters.OperationTimeLte); + Assert.False(parameters.RawQueryData.ContainsKey("operation_time[lte]")); + } +} diff --git a/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListResponseTest.cs b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListResponseTest.cs new file mode 100644 index 00000000..651dfece --- /dev/null +++ b/src/Orb.Tests/Models/Customers/BalanceTransactions/BalanceTransactionListResponseTest.cs @@ -0,0 +1,274 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Tests.Models.Customers.BalanceTransactions; + +public class BalanceTransactionListResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BalanceTransactionListResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }; + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = + BalanceTransactionListResponseAction.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = + BalanceTransactionListResponseType.Increment; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAction, model.Action); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNote, model.CreditNote); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedInvoice, model.Invoice); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BalanceTransactionListResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BalanceTransactionListResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = + BalanceTransactionListResponseAction.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = + BalanceTransactionListResponseType.Increment; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAction, deserialized.Action); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNote, deserialized.CreditNote); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedInvoice, deserialized.Invoice); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new BalanceTransactionListResponse + { + ID = "cgZa3SXcsPTVyC4Y", + Action = BalanceTransactionListResponseAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = BalanceTransactionListResponseType.Increment, + }; + + model.Validate(); + } +} + +public class BalanceTransactionListResponseActionTest : TestBase +{ + [Theory] + [InlineData(BalanceTransactionListResponseAction.AppliedToInvoice)] + [InlineData(BalanceTransactionListResponseAction.ManualAdjustment)] + [InlineData(BalanceTransactionListResponseAction.ProratedRefund)] + [InlineData(BalanceTransactionListResponseAction.RevertProratedRefund)] + [InlineData(BalanceTransactionListResponseAction.ReturnFromVoiding)] + [InlineData(BalanceTransactionListResponseAction.CreditNoteApplied)] + [InlineData(BalanceTransactionListResponseAction.CreditNoteVoided)] + [InlineData(BalanceTransactionListResponseAction.OverpaymentRefund)] + [InlineData(BalanceTransactionListResponseAction.ExternalPayment)] + [InlineData(BalanceTransactionListResponseAction.SmallInvoiceCarryover)] + public void Validation_Works(BalanceTransactionListResponseAction rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BalanceTransactionListResponseAction.AppliedToInvoice)] + [InlineData(BalanceTransactionListResponseAction.ManualAdjustment)] + [InlineData(BalanceTransactionListResponseAction.ProratedRefund)] + [InlineData(BalanceTransactionListResponseAction.RevertProratedRefund)] + [InlineData(BalanceTransactionListResponseAction.ReturnFromVoiding)] + [InlineData(BalanceTransactionListResponseAction.CreditNoteApplied)] + [InlineData(BalanceTransactionListResponseAction.CreditNoteVoided)] + [InlineData(BalanceTransactionListResponseAction.OverpaymentRefund)] + [InlineData(BalanceTransactionListResponseAction.ExternalPayment)] + [InlineData(BalanceTransactionListResponseAction.SmallInvoiceCarryover)] + public void SerializationRoundtrip_Works(BalanceTransactionListResponseAction rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BalanceTransactionListResponseTypeTest : TestBase +{ + [Theory] + [InlineData(BalanceTransactionListResponseType.Increment)] + [InlineData(BalanceTransactionListResponseType.Decrement)] + public void Validation_Works(BalanceTransactionListResponseType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BalanceTransactionListResponseType.Increment)] + [InlineData(BalanceTransactionListResponseType.Decrement)] + public void SerializationRoundtrip_Works(BalanceTransactionListResponseType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Costs/CostListByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Costs/CostListByExternalIDParamsTest.cs new file mode 100644 index 00000000..c893eafe --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Costs/CostListByExternalIDParamsTest.cs @@ -0,0 +1,133 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Costs; + +namespace Orb.Tests.Models.Customers.Costs; + +public class CostListByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CostListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + TimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"), + TimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"), + ViewMode = CostListByExternalIDParamsViewMode.Periodic, + }; + + string expectedExternalCustomerID = "external_customer_id"; + string expectedCurrency = "currency"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"); + ApiEnum expectedViewMode = + CostListByExternalIDParamsViewMode.Periodic; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedViewMode, parameters.ViewMode); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CostListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CostListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + + Currency = null, + TimeframeEnd = null, + TimeframeStart = null, + ViewMode = null, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } +} + +public class CostListByExternalIDParamsViewModeTest : TestBase +{ + [Theory] + [InlineData(CostListByExternalIDParamsViewMode.Periodic)] + [InlineData(CostListByExternalIDParamsViewMode.Cumulative)] + public void Validation_Works(CostListByExternalIDParamsViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CostListByExternalIDParamsViewMode.Periodic)] + [InlineData(CostListByExternalIDParamsViewMode.Cumulative)] + public void SerializationRoundtrip_Works(CostListByExternalIDParamsViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Costs/CostListByExternalIDResponseTest.cs b/src/Orb.Tests/Models/Customers/Costs/CostListByExternalIDResponseTest.cs new file mode 100644 index 00000000..95bde83c --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Costs/CostListByExternalIDResponseTest.cs @@ -0,0 +1,871 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers.Costs; + +namespace Orb.Tests.Models.Customers.Costs; + +public class CostListByExternalIDResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CostListByExternalIDResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + List expectedData = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CostListByExternalIDResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CostListByExternalIDResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CostListByExternalIDResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Costs/CostListParamsTest.cs b/src/Orb.Tests/Models/Customers/Costs/CostListParamsTest.cs new file mode 100644 index 00000000..e524f104 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Costs/CostListParamsTest.cs @@ -0,0 +1,131 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Costs; + +namespace Orb.Tests.Models.Customers.Costs; + +public class CostListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CostListParams + { + CustomerID = "customer_id", + Currency = "currency", + TimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"), + TimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"), + ViewMode = ViewMode.Periodic, + }; + + string expectedCustomerID = "customer_id"; + string expectedCurrency = "currency"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"); + ApiEnum expectedViewMode = ViewMode.Periodic; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedViewMode, parameters.ViewMode); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CostListParams { CustomerID = "customer_id" }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CostListParams + { + CustomerID = "customer_id", + + Currency = null, + TimeframeEnd = null, + TimeframeStart = null, + ViewMode = null, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } +} + +public class ViewModeTest : TestBase +{ + [Theory] + [InlineData(ViewMode.Periodic)] + [InlineData(ViewMode.Cumulative)] + public void Validation_Works(ViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ViewMode.Periodic)] + [InlineData(ViewMode.Cumulative)] + public void SerializationRoundtrip_Works(ViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Costs/CostListResponseTest.cs b/src/Orb.Tests/Models/Customers/Costs/CostListResponseTest.cs new file mode 100644 index 00000000..15c5b472 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Costs/CostListResponseTest.cs @@ -0,0 +1,871 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers.Costs; + +namespace Orb.Tests.Models.Customers.Costs; + +public class CostListResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CostListResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + List expectedData = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CostListResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CostListResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CostListResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDPageResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDPageResponseTest.cs new file mode 100644 index 00000000..12e2b8f5 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDPageResponseTest.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers.Credits; + +namespace Orb.Tests.Models.Customers.Credits; + +public class CreditListByExternalIDPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDParamsTest.cs new file mode 100644 index 00000000..cf1730b3 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDParamsTest.cs @@ -0,0 +1,102 @@ +using Orb.Models.Customers.Credits; + +namespace Orb.Tests.Models.Customers.Credits; + +public class CreditListByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CreditListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + Cursor = "cursor", + IncludeAllBlocks = true, + Limit = 1, + }; + + string expectedExternalCustomerID = "external_customer_id"; + string expectedCurrency = "currency"; + string expectedCursor = "cursor"; + bool expectedIncludeAllBlocks = true; + long expectedLimit = 1; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedIncludeAllBlocks, parameters.IncludeAllBlocks); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + Cursor = "cursor", + }; + + Assert.Null(parameters.IncludeAllBlocks); + Assert.False(parameters.RawQueryData.ContainsKey("include_all_blocks")); + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new CreditListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Currency = "currency", + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + IncludeAllBlocks = null, + Limit = null, + }; + + Assert.Null(parameters.IncludeAllBlocks); + Assert.False(parameters.RawQueryData.ContainsKey("include_all_blocks")); + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + IncludeAllBlocks = true, + Limit = 1, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CreditListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + IncludeAllBlocks = true, + Limit = 1, + + Currency = null, + Cursor = null, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDResponseTest.cs new file mode 100644 index 00000000..981369e1 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/CreditListByExternalIDResponseTest.cs @@ -0,0 +1,446 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits; + +namespace Orb.Tests.Models.Customers.Credits; + +public class CreditListByExternalIDResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditListByExternalIDResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }; + + string expectedID = "id"; + double expectedBalance = 0; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedMaximumInitialBalance = 0; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + ApiEnum expectedStatus = + CreditListByExternalIDResponseStatus.Active; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBalance, model.Balance); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedMaximumInitialBalance, model.MaximumInitialBalance); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + Assert.Equal(expectedStatus, model.Status); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditListByExternalIDResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditListByExternalIDResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedBalance = 0; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedMaximumInitialBalance = 0; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + ApiEnum expectedStatus = + CreditListByExternalIDResponseStatus.Active; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBalance, deserialized.Balance); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedMaximumInitialBalance, deserialized.MaximumInitialBalance); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + Assert.Equal(expectedStatus, deserialized.Status); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditListByExternalIDResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = CreditListByExternalIDResponseStatus.Active, + }; + + model.Validate(); + } +} + +public class CreditListByExternalIDResponseFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditListByExternalIDResponseFilter + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + CreditListByExternalIDResponseFilterField.ItemID; + ApiEnum expectedOperator = + CreditListByExternalIDResponseFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditListByExternalIDResponseFilter + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditListByExternalIDResponseFilter + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + CreditListByExternalIDResponseFilterField.ItemID; + ApiEnum expectedOperator = + CreditListByExternalIDResponseFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CreditListByExternalIDResponseFilter + { + Field = CreditListByExternalIDResponseFilterField.ItemID, + Operator = CreditListByExternalIDResponseFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class CreditListByExternalIDResponseFilterFieldTest : TestBase +{ + [Theory] + [InlineData(CreditListByExternalIDResponseFilterField.ItemID)] + public void Validation_Works(CreditListByExternalIDResponseFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CreditListByExternalIDResponseFilterField.ItemID)] + public void SerializationRoundtrip_Works(CreditListByExternalIDResponseFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CreditListByExternalIDResponseFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(CreditListByExternalIDResponseFilterOperator.Includes)] + [InlineData(CreditListByExternalIDResponseFilterOperator.Excludes)] + public void Validation_Works(CreditListByExternalIDResponseFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CreditListByExternalIDResponseFilterOperator.Includes)] + [InlineData(CreditListByExternalIDResponseFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(CreditListByExternalIDResponseFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CreditListByExternalIDResponseStatusTest : TestBase +{ + [Theory] + [InlineData(CreditListByExternalIDResponseStatus.Active)] + [InlineData(CreditListByExternalIDResponseStatus.PendingPayment)] + public void Validation_Works(CreditListByExternalIDResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CreditListByExternalIDResponseStatus.Active)] + [InlineData(CreditListByExternalIDResponseStatus.PendingPayment)] + public void SerializationRoundtrip_Works(CreditListByExternalIDResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/CreditListPageResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/CreditListPageResponseTest.cs new file mode 100644 index 00000000..5f1a6d4e --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/CreditListPageResponseTest.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits; + +public class CreditListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditListPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditListPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditListPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditListPageResponse + { + Data = + [ + new() + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/CreditListParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/CreditListParamsTest.cs new file mode 100644 index 00000000..8dbaac16 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/CreditListParamsTest.cs @@ -0,0 +1,102 @@ +using Orb.Models.Customers.Credits; + +namespace Orb.Tests.Models.Customers.Credits; + +public class CreditListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CreditListParams + { + CustomerID = "customer_id", + Currency = "currency", + Cursor = "cursor", + IncludeAllBlocks = true, + Limit = 1, + }; + + string expectedCustomerID = "customer_id"; + string expectedCurrency = "currency"; + string expectedCursor = "cursor"; + bool expectedIncludeAllBlocks = true; + long expectedLimit = 1; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedIncludeAllBlocks, parameters.IncludeAllBlocks); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditListParams + { + CustomerID = "customer_id", + Currency = "currency", + Cursor = "cursor", + }; + + Assert.Null(parameters.IncludeAllBlocks); + Assert.False(parameters.RawQueryData.ContainsKey("include_all_blocks")); + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new CreditListParams + { + CustomerID = "customer_id", + Currency = "currency", + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + IncludeAllBlocks = null, + Limit = null, + }; + + Assert.Null(parameters.IncludeAllBlocks); + Assert.False(parameters.RawQueryData.ContainsKey("include_all_blocks")); + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CreditListParams + { + CustomerID = "customer_id", + IncludeAllBlocks = true, + Limit = 1, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CreditListParams + { + CustomerID = "customer_id", + IncludeAllBlocks = true, + Limit = 1, + + Currency = null, + Cursor = null, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/CreditListResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/CreditListResponseTest.cs new file mode 100644 index 00000000..c82214e1 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/CreditListResponseTest.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits; + +namespace Orb.Tests.Models.Customers.Credits; + +public class CreditListResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditListResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }; + + string expectedID = "id"; + double expectedBalance = 0; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ]; + double expectedMaximumInitialBalance = 0; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + ApiEnum expectedStatus = Status.Active; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBalance, model.Balance); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedMaximumInitialBalance, model.MaximumInitialBalance); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + Assert.Equal(expectedStatus, model.Status); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditListResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditListResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedBalance = 0; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ]; + double expectedMaximumInitialBalance = 0; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + ApiEnum expectedStatus = Status.Active; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBalance, deserialized.Balance); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedMaximumInitialBalance, deserialized.MaximumInitialBalance); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + Assert.Equal(expectedStatus, deserialized.Status); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditListResponse + { + ID = "id", + Balance = 0, + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + MaximumInitialBalance = 0, + PerUnitCostBasis = "per_unit_cost_basis", + Status = Status.Active, + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Filter + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = Field.ItemID; + ApiEnum expectedOperator = Operator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Filter + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Filter + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = Field.ItemID; + ApiEnum expectedOperator = Operator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Filter + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class FieldTest : TestBase +{ + [Theory] + [InlineData(Field.ItemID)] + public void Validation_Works(Field rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Field.ItemID)] + public void SerializationRoundtrip_Works(Field rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class OperatorTest : TestBase +{ + [Theory] + [InlineData(Operator.Includes)] + [InlineData(Operator.Excludes)] + public void Validation_Works(Operator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Operator.Includes)] + [InlineData(Operator.Excludes)] + public void SerializationRoundtrip_Works(Operator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.PendingPayment)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.PendingPayment)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/AffectedBlockTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/AffectedBlockTest.cs new file mode 100644 index 00000000..30a5550a --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/AffectedBlockTest.cs @@ -0,0 +1,352 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class AffectedBlockTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AffectedBlock + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string expectedID = "id"; + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AffectedBlock + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AffectedBlock + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + } + + [Fact] + public void Validation_Works() + { + var model = new AffectedBlock + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + + model.Validate(); + } +} + +public class AffectedBlockFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AffectedBlockFilter + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = AffectedBlockFilterField.PriceID; + ApiEnum expectedOperator = + AffectedBlockFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AffectedBlockFilter + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AffectedBlockFilter + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = AffectedBlockFilterField.PriceID; + ApiEnum expectedOperator = + AffectedBlockFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AffectedBlockFilter + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class AffectedBlockFilterFieldTest : TestBase +{ + [Theory] + [InlineData(AffectedBlockFilterField.PriceID)] + [InlineData(AffectedBlockFilterField.ItemID)] + [InlineData(AffectedBlockFilterField.PriceType)] + [InlineData(AffectedBlockFilterField.Currency)] + [InlineData(AffectedBlockFilterField.PricingUnitID)] + public void Validation_Works(AffectedBlockFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AffectedBlockFilterField.PriceID)] + [InlineData(AffectedBlockFilterField.ItemID)] + [InlineData(AffectedBlockFilterField.PriceType)] + [InlineData(AffectedBlockFilterField.Currency)] + [InlineData(AffectedBlockFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(AffectedBlockFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AffectedBlockFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(AffectedBlockFilterOperator.Includes)] + [InlineData(AffectedBlockFilterOperator.Excludes)] + public void Validation_Works(AffectedBlockFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AffectedBlockFilterOperator.Includes)] + [InlineData(AffectedBlockFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(AffectedBlockFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/AmendmentLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/AmendmentLedgerEntryTest.cs new file mode 100644 index 00000000..25e17eb6 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/AmendmentLedgerEntryTest.cs @@ -0,0 +1,381 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class AmendmentLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AmendmentLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + AmendmentLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + AmendmentLedgerEntryEntryType.Amendment; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, model.StartingBalance); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AmendmentLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AmendmentLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + AmendmentLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + AmendmentLedgerEntryEntryType.Amendment; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + } + + [Fact] + public void Validation_Works() + { + var model = new AmendmentLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + model.Validate(); + } +} + +public class AmendmentLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(AmendmentLedgerEntryEntryStatus.Committed)] + [InlineData(AmendmentLedgerEntryEntryStatus.Pending)] + public void Validation_Works(AmendmentLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmendmentLedgerEntryEntryStatus.Committed)] + [InlineData(AmendmentLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(AmendmentLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class AmendmentLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(AmendmentLedgerEntryEntryType.Amendment)] + public void Validation_Works(AmendmentLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AmendmentLedgerEntryEntryType.Amendment)] + public void SerializationRoundtrip_Works(AmendmentLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryTest.cs new file mode 100644 index 00000000..92e7f2b3 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryTest.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class CreditBlockExpiryLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CreditBlockExpiryLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + CreditBlockExpiryLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, model.StartingBalance); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CreditBlockExpiryLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CreditBlockExpiryLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + CreditBlockExpiryLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + } + + [Fact] + public void Validation_Works() + { + var model = new CreditBlockExpiryLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + model.Validate(); + } +} + +public class CreditBlockExpiryLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(CreditBlockExpiryLedgerEntryEntryStatus.Committed)] + [InlineData(CreditBlockExpiryLedgerEntryEntryStatus.Pending)] + public void Validation_Works(CreditBlockExpiryLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CreditBlockExpiryLedgerEntryEntryStatus.Committed)] + [InlineData(CreditBlockExpiryLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(CreditBlockExpiryLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CreditBlockExpiryLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry)] + public void Validation_Works(CreditBlockExpiryLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry)] + public void SerializationRoundtrip_Works(CreditBlockExpiryLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/DecrementLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/DecrementLedgerEntryTest.cs new file mode 100644 index 00000000..3cfd6557 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/DecrementLedgerEntryTest.cs @@ -0,0 +1,571 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class DecrementLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + DecrementLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + DecrementLedgerEntryEntryType.Decrement; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + string expectedEventID = "event_id"; + string expectedInvoiceID = "invoice_id"; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedEventID, model.EventID); + Assert.Equal(expectedInvoiceID, model.InvoiceID); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + DecrementLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + DecrementLedgerEntryEntryType.Decrement; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + string expectedEventID = "event_id"; + string expectedInvoiceID = "invoice_id"; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedEventID, deserialized.EventID); + Assert.Equal(expectedInvoiceID, deserialized.InvoiceID); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + Assert.Null(model.EventID); + Assert.False(model.RawData.ContainsKey("event_id")); + Assert.Null(model.InvoiceID); + Assert.False(model.RawData.ContainsKey("invoice_id")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + + EventID = null, + InvoiceID = null, + PriceID = null, + }; + + Assert.Null(model.EventID); + Assert.True(model.RawData.ContainsKey("event_id")); + Assert.Null(model.InvoiceID); + Assert.True(model.RawData.ContainsKey("invoice_id")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new DecrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + + EventID = null, + InvoiceID = null, + PriceID = null, + }; + + model.Validate(); + } +} + +public class DecrementLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(DecrementLedgerEntryEntryStatus.Committed)] + [InlineData(DecrementLedgerEntryEntryStatus.Pending)] + public void Validation_Works(DecrementLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DecrementLedgerEntryEntryStatus.Committed)] + [InlineData(DecrementLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(DecrementLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class DecrementLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(DecrementLedgerEntryEntryType.Decrement)] + public void Validation_Works(DecrementLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DecrementLedgerEntryEntryType.Decrement)] + public void SerializationRoundtrip_Works(DecrementLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryTest.cs new file mode 100644 index 00000000..98b8ea0a --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryTest.cs @@ -0,0 +1,401 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class ExpirationChangeLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ExpirationChangeLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + ExpirationChangeLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + ExpirationChangeLedgerEntryEntryType.ExpirationChange; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + DateTimeOffset expectedNewBlockExpiryDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + double expectedStartingBalance = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedNewBlockExpiryDate, model.NewBlockExpiryDate); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ExpirationChangeLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ExpirationChangeLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + ExpirationChangeLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + ExpirationChangeLedgerEntryEntryType.ExpirationChange; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + DateTimeOffset expectedNewBlockExpiryDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + double expectedStartingBalance = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedNewBlockExpiryDate, deserialized.NewBlockExpiryDate); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + } + + [Fact] + public void Validation_Works() + { + var model = new ExpirationChangeLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + }; + + model.Validate(); + } +} + +public class ExpirationChangeLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(ExpirationChangeLedgerEntryEntryStatus.Committed)] + [InlineData(ExpirationChangeLedgerEntryEntryStatus.Pending)] + public void Validation_Works(ExpirationChangeLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ExpirationChangeLedgerEntryEntryStatus.Committed)] + [InlineData(ExpirationChangeLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(ExpirationChangeLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ExpirationChangeLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(ExpirationChangeLedgerEntryEntryType.ExpirationChange)] + public void Validation_Works(ExpirationChangeLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ExpirationChangeLedgerEntryEntryType.ExpirationChange)] + public void SerializationRoundtrip_Works(ExpirationChangeLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/IncrementLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/IncrementLedgerEntryTest.cs new file mode 100644 index 00000000..84859635 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/IncrementLedgerEntryTest.cs @@ -0,0 +1,2593 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class IncrementLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + Models::CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + IncrementLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + IncrementLedgerEntryEntryType.Increment; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + List expectedCreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.NotNull(model.CreatedInvoices); + Assert.Equal(expectedCreatedInvoices.Count, model.CreatedInvoices.Count); + for (int i = 0; i < expectedCreatedInvoices.Count; i++) + { + Assert.Equal(expectedCreatedInvoices[i], model.CreatedInvoices[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + Models::CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + IncrementLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + IncrementLedgerEntryEntryType.Increment; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + List expectedCreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.NotNull(deserialized.CreatedInvoices); + Assert.Equal(expectedCreatedInvoices.Count, deserialized.CreatedInvoices.Count); + for (int i = 0; i < expectedCreatedInvoices.Count; i++) + { + Assert.Equal(expectedCreatedInvoices[i], deserialized.CreatedInvoices[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + Assert.Null(model.CreatedInvoices); + Assert.False(model.RawData.ContainsKey("created_invoices")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + + CreatedInvoices = null, + }; + + Assert.Null(model.CreatedInvoices); + Assert.True(model.RawData.ContainsKey("created_invoices")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new IncrementLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + + CreatedInvoices = null, + }; + + model.Validate(); + } +} + +public class IncrementLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(IncrementLedgerEntryEntryStatus.Committed)] + [InlineData(IncrementLedgerEntryEntryStatus.Pending)] + public void Validation_Works(IncrementLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(IncrementLedgerEntryEntryStatus.Committed)] + [InlineData(IncrementLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(IncrementLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class IncrementLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(IncrementLedgerEntryEntryType.Increment)] + public void Validation_Works(IncrementLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(IncrementLedgerEntryEntryType.Increment)] + public void SerializationRoundtrip_Works(IncrementLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsTest.cs new file mode 100644 index 00000000..69d26dc3 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsTest.cs @@ -0,0 +1,2068 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerCreateEntryByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new LedgerCreateEntryByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Body = new LedgerCreateEntryByExternalIDParamsBodyIncrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }, + }; + + string expectedExternalCustomerID = "external_customer_id"; + LedgerCreateEntryByExternalIDParamsBody expectedBody = + new LedgerCreateEntryByExternalIDParamsBodyIncrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedBody, parameters.Body); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyTest : TestBase +{ + [Fact] + public void IncrementValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyIncrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + } + ); + value.Validate(); + } + + [Fact] + public void DecrementValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyDecrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void ExpirationChangeValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyExpirationChange() + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void VoidValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyVoid() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + } + ); + value.Validate(); + } + + [Fact] + public void AmendmentValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyAmendment() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void IncrementSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyIncrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DecrementSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyDecrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ExpirationChangeSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyExpirationChange() + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyVoid() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmendmentSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBody value = new( + new LedgerCreateEntryByExternalIDParamsBodyAmendment() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"increment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ]; + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings expectedInvoiceSettings = + new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedAmount, model.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedInvoiceSettings, model.InvoiceSettings); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"increment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ]; + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings expectedInvoiceSettings = + new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedInvoiceSettings, deserialized.InvoiceSettings); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement { Amount = 0 }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.EffectiveDate); + Assert.False(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.ExpiryDate); + Assert.False(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.InvoiceSettings); + Assert.False(model.RawData.ContainsKey("invoice_settings")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.PerUnitCostBasis); + Assert.False(model.RawData.ContainsKey("per_unit_cost_basis")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement { Amount = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement + { + Amount = 0, + + Currency = null, + Description = null, + EffectiveDate = null, + ExpiryDate = null, + Filters = null, + InvoiceSettings = null, + Metadata = null, + PerUnitCostBasis = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.EffectiveDate); + Assert.True(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.ExpiryDate); + Assert.True(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.InvoiceSettings); + Assert.True(model.RawData.ContainsKey("invoice_settings")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.PerUnitCostBasis); + Assert.True(model.RawData.ContainsKey("per_unit_cost_basis")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrement + { + Amount = 0, + + Currency = null, + Description = null, + EffectiveDate = null, + ExpiryDate = null, + Filters = null, + InvoiceSettings = null, + Metadata = null, + PerUnitCostBasis = null, + }; + + model.Validate(); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementFilter + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID; + ApiEnum< + string, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator + > expectedOperator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementFilter + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementFilter + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID; + ApiEnum< + string, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator + > expectedOperator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementFilter + { + Field = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementFilterFieldTest : TestBase +{ + [Theory] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID)] + public void Validation_Works( + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID)] + public void SerializationRoundtrip_Works( + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes)] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Excludes)] + public void Validation_Works( + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes)] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + bool expectedAutoCollection = true; + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate expectedCustomDueDate = + "2019-12-27"; + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate expectedInvoiceDate = + "2019-12-27"; + string expectedItemID = "item_id"; + string expectedMemo = "memo"; + long expectedNetTerms = 0; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedCustomDueDate, model.CustomDueDate); + Assert.Equal(expectedInvoiceDate, model.InvoiceDate); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedRequireSuccessfulPayment, model.RequireSuccessfulPayment); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedAutoCollection = true; + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate expectedCustomDueDate = + "2019-12-27"; + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate expectedInvoiceDate = + "2019-12-27"; + string expectedItemID = "item_id"; + string expectedMemo = "memo"; + long expectedNetTerms = 0; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedCustomDueDate, deserialized.CustomDueDate); + Assert.Equal(expectedInvoiceDate, deserialized.InvoiceDate); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedRequireSuccessfulPayment, deserialized.RequireSuccessfulPayment); + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + }; + + Assert.Null(model.CustomDueDate); + Assert.False(model.RawData.ContainsKey("custom_due_date")); + Assert.Null(model.InvoiceDate); + Assert.False(model.RawData.ContainsKey("invoice_date")); + Assert.Null(model.ItemID); + Assert.False(model.RawData.ContainsKey("item_id")); + Assert.Null(model.Memo); + Assert.False(model.RawData.ContainsKey("memo")); + Assert.Null(model.NetTerms); + Assert.False(model.RawData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + + CustomDueDate = null, + InvoiceDate = null, + ItemID = null, + Memo = null, + NetTerms = null, + }; + + Assert.Null(model.CustomDueDate); + Assert.True(model.RawData.ContainsKey("custom_due_date")); + Assert.Null(model.InvoiceDate); + Assert.True(model.RawData.ContainsKey("invoice_date")); + Assert.Null(model.ItemID); + Assert.True(model.RawData.ContainsKey("item_id")); + Assert.Null(model.Memo); + Assert.True(model.RawData.ContainsKey("memo")); + Assert.Null(model.NetTerms); + Assert.True(model.RawData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + + CustomDueDate = null, + InvoiceDate = null, + ItemID = null, + Memo = null, + NetTerms = null, + }; + + model.Validate(); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDateTest + : TestBase +{ + [Fact] + public void DateValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate value = new( + "2019-12-27" + ); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate value = new( + "2019-12-27" + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDateTest + : TestBase +{ + [Fact] + public void DateValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate value = new( + "2019-12-27" + ); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate value = new( + "2019-12-27" + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyDecrementTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"decrement\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, model.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"decrement\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement { Amount = 0 }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement { Amount = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement + { + Amount = 0, + + Currency = null, + Description = null, + Metadata = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyDecrement + { + Amount = 0, + + Currency = null, + Description = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyExpirationChangeTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + JsonElement expectedEntryType = JsonSerializer.Deserialize( + "\"expiration_change\"" + ); + string expectedTargetExpiryDate = "2019-12-27"; + double expectedAmount = 0; + string expectedBlockID = "block_id"; + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedTargetExpiryDate, model.TargetExpiryDate); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedBlockID, model.BlockID); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + JsonElement expectedEntryType = JsonSerializer.Deserialize( + "\"expiration_change\"" + ); + string expectedTargetExpiryDate = "2019-12-27"; + double expectedAmount = 0; + string expectedBlockID = "block_id"; + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedTargetExpiryDate, deserialized.TargetExpiryDate); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedBlockID, deserialized.BlockID); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + }; + + Assert.Null(model.Amount); + Assert.False(model.RawData.ContainsKey("amount")); + Assert.Null(model.BlockID); + Assert.False(model.RawData.ContainsKey("block_id")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.ExpiryDate); + Assert.False(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + + Amount = null, + BlockID = null, + Currency = null, + Description = null, + ExpiryDate = null, + Metadata = null, + }; + + Assert.Null(model.Amount); + Assert.True(model.RawData.ContainsKey("amount")); + Assert.Null(model.BlockID); + Assert.True(model.RawData.ContainsKey("block_id")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.ExpiryDate); + Assert.True(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyExpirationChange + { + TargetExpiryDate = "2019-12-27", + + Amount = null, + BlockID = null, + Currency = null, + Description = null, + ExpiryDate = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyVoidTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + }; + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"void\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + ApiEnum expectedVoidReason = + LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedBlockID, model.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedVoidReason, model.VoidReason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"void\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + ApiEnum expectedVoidReason = + LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedBlockID, deserialized.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedVoidReason, deserialized.VoidReason); + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.VoidReason); + Assert.False(model.RawData.ContainsKey("void_reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + VoidReason = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.VoidReason); + Assert.True(model.RawData.ContainsKey("void_reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyVoid + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + VoidReason = null, + }; + + model.Validate(); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyVoidVoidReasonTest : TestBase +{ + [Theory] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund)] + public void Validation_Works(LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund)] + public void SerializationRoundtrip_Works( + LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerCreateEntryByExternalIDParamsBodyAmendmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"amendment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedBlockID, model.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"amendment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedBlockID, deserialized.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new LedgerCreateEntryByExternalIDParamsBodyAmendment + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponseTest.cs new file mode 100644 index 00000000..38a38be3 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponseTest.cs @@ -0,0 +1,1315 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerCreateEntryByExternalIDResponseTest : TestBase +{ + [Fact] + public void IncrementLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + value.Validate(); + } + + [Fact] + public void DecrementLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + value.Validate(); + } + + [Fact] + public void ExpirationChangeLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void CreditBlockExpiryLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void VoidLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void VoidInitiatedLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmendmentLedgerEntryValidationWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void IncrementLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DecrementLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ExpirationChangeLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CreditBlockExpiryLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidInitiatedLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmendmentLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryByExternalIDResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsTest.cs new file mode 100644 index 00000000..83b34fef --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsTest.cs @@ -0,0 +1,1931 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Ledger = Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerCreateEntryParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new Ledger::LedgerCreateEntryParams + { + CustomerID = "customer_id", + Body = new Ledger::Increment() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }, + }; + + string expectedCustomerID = "customer_id"; + Ledger::Body expectedBody = new Ledger::Increment() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedBody, parameters.Body); + } +} + +public class BodyTest : TestBase +{ + [Fact] + public void IncrementValidationWorks() + { + Ledger::Body value = new( + new Ledger::Increment() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + } + ); + value.Validate(); + } + + [Fact] + public void DecrementValidationWorks() + { + Ledger::Body value = new( + new Ledger::Decrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void ExpirationChangeValidationWorks() + { + Ledger::Body value = new( + new Ledger::ExpirationChange() + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void VoidValidationWorks() + { + Ledger::Body value = new( + new Ledger::Void() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = Ledger::VoidReason.Refund, + } + ); + value.Validate(); + } + + [Fact] + public void AmendmentValidationWorks() + { + Ledger::Body value = new( + new Ledger::Amendment() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void IncrementSerializationRoundtripWorks() + { + Ledger::Body value = new( + new Ledger::Increment() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DecrementSerializationRoundtripWorks() + { + Ledger::Body value = new( + new Ledger::Decrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ExpirationChangeSerializationRoundtripWorks() + { + Ledger::Body value = new( + new Ledger::ExpirationChange() + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidSerializationRoundtripWorks() + { + Ledger::Body value = new( + new Ledger::Void() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = Ledger::VoidReason.Refund, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmendmentSerializationRoundtripWorks() + { + Ledger::Body value = new( + new Ledger::Amendment() + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class IncrementTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::Increment + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"increment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ]; + Ledger::InvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedAmount, model.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedInvoiceSettings, model.InvoiceSettings); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::Increment + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::Increment + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"increment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ]; + Ledger::InvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedInvoiceSettings, deserialized.InvoiceSettings); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::Increment + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::Increment { Amount = 0 }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.EffectiveDate); + Assert.False(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.ExpiryDate); + Assert.False(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.InvoiceSettings); + Assert.False(model.RawData.ContainsKey("invoice_settings")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.PerUnitCostBasis); + Assert.False(model.RawData.ContainsKey("per_unit_cost_basis")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::Increment { Amount = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Ledger::Increment + { + Amount = 0, + + Currency = null, + Description = null, + EffectiveDate = null, + ExpiryDate = null, + Filters = null, + InvoiceSettings = null, + Metadata = null, + PerUnitCostBasis = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.EffectiveDate); + Assert.True(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.ExpiryDate); + Assert.True(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.InvoiceSettings); + Assert.True(model.RawData.ContainsKey("invoice_settings")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.PerUnitCostBasis); + Assert.True(model.RawData.ContainsKey("per_unit_cost_basis")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::Increment + { + Amount = 0, + + Currency = null, + Description = null, + EffectiveDate = null, + ExpiryDate = null, + Filters = null, + InvoiceSettings = null, + Metadata = null, + PerUnitCostBasis = null, + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::Filter + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = Ledger::Field.ItemID; + ApiEnum expectedOperator = Ledger::Operator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::Filter + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::Filter + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = Ledger::Field.ItemID; + ApiEnum expectedOperator = Ledger::Operator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::Filter + { + Field = Ledger::Field.ItemID, + Operator = Ledger::Operator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class FieldTest : TestBase +{ + [Theory] + [InlineData(Ledger::Field.ItemID)] + public void Validation_Works(Ledger::Field rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Ledger::Field.ItemID)] + public void SerializationRoundtrip_Works(Ledger::Field rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class OperatorTest : TestBase +{ + [Theory] + [InlineData(Ledger::Operator.Includes)] + [InlineData(Ledger::Operator.Excludes)] + public void Validation_Works(Ledger::Operator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Ledger::Operator.Includes)] + [InlineData(Ledger::Operator.Excludes)] + public void SerializationRoundtrip_Works(Ledger::Operator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceSettingsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + bool expectedAutoCollection = true; + Ledger::CustomDueDate expectedCustomDueDate = "2019-12-27"; + Ledger::InvoiceDate expectedInvoiceDate = "2019-12-27"; + string expectedItemID = "item_id"; + string expectedMemo = "memo"; + long expectedNetTerms = 0; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedCustomDueDate, model.CustomDueDate); + Assert.Equal(expectedInvoiceDate, model.InvoiceDate); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedRequireSuccessfulPayment, model.RequireSuccessfulPayment); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedAutoCollection = true; + Ledger::CustomDueDate expectedCustomDueDate = "2019-12-27"; + Ledger::InvoiceDate expectedInvoiceDate = "2019-12-27"; + string expectedItemID = "item_id"; + string expectedMemo = "memo"; + long expectedNetTerms = 0; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedCustomDueDate, deserialized.CustomDueDate); + Assert.Equal(expectedInvoiceDate, deserialized.InvoiceDate); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedRequireSuccessfulPayment, deserialized.RequireSuccessfulPayment); + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + }; + + Assert.Null(model.CustomDueDate); + Assert.False(model.RawData.ContainsKey("custom_due_date")); + Assert.Null(model.InvoiceDate); + Assert.False(model.RawData.ContainsKey("invoice_date")); + Assert.Null(model.ItemID); + Assert.False(model.RawData.ContainsKey("item_id")); + Assert.Null(model.Memo); + Assert.False(model.RawData.ContainsKey("memo")); + Assert.Null(model.NetTerms); + Assert.False(model.RawData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + + CustomDueDate = null, + InvoiceDate = null, + ItemID = null, + Memo = null, + NetTerms = null, + }; + + Assert.Null(model.CustomDueDate); + Assert.True(model.RawData.ContainsKey("custom_due_date")); + Assert.Null(model.InvoiceDate); + Assert.True(model.RawData.ContainsKey("invoice_date")); + Assert.Null(model.ItemID); + Assert.True(model.RawData.ContainsKey("item_id")); + Assert.Null(model.Memo); + Assert.True(model.RawData.ContainsKey("memo")); + Assert.Null(model.NetTerms); + Assert.True(model.RawData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::InvoiceSettings + { + AutoCollection = true, + RequireSuccessfulPayment = true, + + CustomDueDate = null, + InvoiceDate = null, + ItemID = null, + Memo = null, + NetTerms = null, + }; + + model.Validate(); + } +} + +public class CustomDueDateTest : TestBase +{ + [Fact] + public void DateValidationWorks() + { + Ledger::CustomDueDate value = new("2019-12-27"); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + Ledger::CustomDueDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + Ledger::CustomDueDate value = new("2019-12-27"); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Ledger::CustomDueDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceDateTest : TestBase +{ + [Fact] + public void DateValidationWorks() + { + Ledger::InvoiceDate value = new("2019-12-27"); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + Ledger::InvoiceDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + Ledger::InvoiceDate value = new("2019-12-27"); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Ledger::InvoiceDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class DecrementTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::Decrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"decrement\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, model.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::Decrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::Decrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"decrement\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::Decrement + { + Amount = 0, + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::Decrement { Amount = 0 }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::Decrement { Amount = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Ledger::Decrement + { + Amount = 0, + + Currency = null, + Description = null, + Metadata = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::Decrement + { + Amount = 0, + + Currency = null, + Description = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class ExpirationChangeTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::ExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + JsonElement expectedEntryType = JsonSerializer.Deserialize( + "\"expiration_change\"" + ); + string expectedTargetExpiryDate = "2019-12-27"; + double expectedAmount = 0; + string expectedBlockID = "block_id"; + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedTargetExpiryDate, model.TargetExpiryDate); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedBlockID, model.BlockID); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedExpiryDate, model.ExpiryDate); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::ExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::ExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + JsonElement expectedEntryType = JsonSerializer.Deserialize( + "\"expiration_change\"" + ); + string expectedTargetExpiryDate = "2019-12-27"; + double expectedAmount = 0; + string expectedBlockID = "block_id"; + string expectedCurrency = "currency"; + string expectedDescription = "description"; + DateTimeOffset expectedExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedTargetExpiryDate, deserialized.TargetExpiryDate); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedBlockID, deserialized.BlockID); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedExpiryDate, deserialized.ExpiryDate); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::ExpirationChange + { + TargetExpiryDate = "2019-12-27", + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::ExpirationChange { TargetExpiryDate = "2019-12-27" }; + + Assert.Null(model.Amount); + Assert.False(model.RawData.ContainsKey("amount")); + Assert.Null(model.BlockID); + Assert.False(model.RawData.ContainsKey("block_id")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.ExpiryDate); + Assert.False(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::ExpirationChange { TargetExpiryDate = "2019-12-27" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Ledger::ExpirationChange + { + TargetExpiryDate = "2019-12-27", + + Amount = null, + BlockID = null, + Currency = null, + Description = null, + ExpiryDate = null, + Metadata = null, + }; + + Assert.Null(model.Amount); + Assert.True(model.RawData.ContainsKey("amount")); + Assert.Null(model.BlockID); + Assert.True(model.RawData.ContainsKey("block_id")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.ExpiryDate); + Assert.True(model.RawData.ContainsKey("expiry_date")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::ExpirationChange + { + TargetExpiryDate = "2019-12-27", + + Amount = null, + BlockID = null, + Currency = null, + Description = null, + ExpiryDate = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class VoidTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::Void + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = Ledger::VoidReason.Refund, + }; + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"void\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + ApiEnum expectedVoidReason = Ledger::VoidReason.Refund; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedBlockID, model.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedVoidReason, model.VoidReason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::Void + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = Ledger::VoidReason.Refund, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::Void + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = Ledger::VoidReason.Refund, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"void\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + ApiEnum expectedVoidReason = Ledger::VoidReason.Refund; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedBlockID, deserialized.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedVoidReason, deserialized.VoidReason); + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::Void + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + VoidReason = Ledger::VoidReason.Refund, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::Void { Amount = 0, BlockID = "block_id" }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.VoidReason); + Assert.False(model.RawData.ContainsKey("void_reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::Void { Amount = 0, BlockID = "block_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Ledger::Void + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + VoidReason = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.VoidReason); + Assert.True(model.RawData.ContainsKey("void_reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::Void + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + VoidReason = null, + }; + + model.Validate(); + } +} + +public class VoidReasonTest : TestBase +{ + [Theory] + [InlineData(Ledger::VoidReason.Refund)] + public void Validation_Works(Ledger::VoidReason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Ledger::VoidReason.Refund)] + public void SerializationRoundtrip_Works(Ledger::VoidReason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AmendmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Ledger::Amendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"amendment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedBlockID, model.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, model.EntryType)); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDescription, model.Description); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Ledger::Amendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Ledger::Amendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmount = 0; + string expectedBlockID = "block_id"; + JsonElement expectedEntryType = JsonSerializer.Deserialize("\"amendment\""); + string expectedCurrency = "currency"; + string expectedDescription = "description"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedBlockID, deserialized.BlockID); + Assert.True(JsonElement.DeepEquals(expectedEntryType, deserialized.EntryType)); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Ledger::Amendment + { + Amount = 0, + BlockID = "block_id", + Currency = "currency", + Description = "description", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Ledger::Amendment { Amount = 0, BlockID = "block_id" }; + + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.False(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Ledger::Amendment { Amount = 0, BlockID = "block_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Ledger::Amendment + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + }; + + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Description); + Assert.True(model.RawData.ContainsKey("description")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Ledger::Amendment + { + Amount = 0, + BlockID = "block_id", + + Currency = null, + Description = null, + Metadata = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryResponseTest.cs new file mode 100644 index 00000000..e1f17fb9 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerCreateEntryResponseTest.cs @@ -0,0 +1,1301 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerCreateEntryResponseTest : TestBase +{ + [Fact] + public void IncrementLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + value.Validate(); + } + + [Fact] + public void DecrementLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + value.Validate(); + } + + [Fact] + public void ExpirationChangeLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void CreditBlockExpiryLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void VoidLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void VoidInitiatedLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmendmentLedgerEntryValidationWorks() + { + LedgerCreateEntryResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void IncrementLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DecrementLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ExpirationChangeLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CreditBlockExpiryLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidInitiatedLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmendmentLedgerEntrySerializationRoundtripWorks() + { + LedgerCreateEntryResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseTest.cs new file mode 100644 index 00000000..1108ff84 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseTest.cs @@ -0,0 +1,2481 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerListByExternalIDPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerListByExternalIDPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerListByExternalIDPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerListByExternalIDPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerListByExternalIDPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsTest.cs new file mode 100644 index 00000000..8582edd1 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsTest.cs @@ -0,0 +1,298 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerListByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new LedgerListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Cursor = "cursor", + EntryStatus = LedgerListByExternalIDParamsEntryStatus.Committed, + EntryType = LedgerListByExternalIDParamsEntryType.Increment, + Limit = 1, + MinimumAmount = "minimum_amount", + }; + + string expectedExternalCustomerID = "external_customer_id"; + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + string expectedCursor = "cursor"; + ApiEnum expectedEntryStatus = + LedgerListByExternalIDParamsEntryStatus.Committed; + ApiEnum expectedEntryType = + LedgerListByExternalIDParamsEntryType.Increment; + long expectedLimit = 1; + string expectedMinimumAmount = "minimum_amount"; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedEntryStatus, parameters.EntryStatus); + Assert.Equal(expectedEntryType, parameters.EntryType); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedMinimumAmount, parameters.MinimumAmount); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new LedgerListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Cursor = "cursor", + EntryStatus = LedgerListByExternalIDParamsEntryStatus.Committed, + EntryType = LedgerListByExternalIDParamsEntryType.Increment, + MinimumAmount = "minimum_amount", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new LedgerListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Cursor = "cursor", + EntryStatus = LedgerListByExternalIDParamsEntryStatus.Committed, + EntryType = LedgerListByExternalIDParamsEntryType.Increment, + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new LedgerListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Limit = 1, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.EntryStatus); + Assert.False(parameters.RawQueryData.ContainsKey("entry_status")); + Assert.Null(parameters.EntryType); + Assert.False(parameters.RawQueryData.ContainsKey("entry_type")); + Assert.Null(parameters.MinimumAmount); + Assert.False(parameters.RawQueryData.ContainsKey("minimum_amount")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new LedgerListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Currency = null, + Cursor = null, + EntryStatus = null, + EntryType = null, + MinimumAmount = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.EntryStatus); + Assert.False(parameters.RawQueryData.ContainsKey("entry_status")); + Assert.Null(parameters.EntryType); + Assert.False(parameters.RawQueryData.ContainsKey("entry_type")); + Assert.Null(parameters.MinimumAmount); + Assert.False(parameters.RawQueryData.ContainsKey("minimum_amount")); + } +} + +public class LedgerListByExternalIDParamsEntryStatusTest : TestBase +{ + [Theory] + [InlineData(LedgerListByExternalIDParamsEntryStatus.Committed)] + [InlineData(LedgerListByExternalIDParamsEntryStatus.Pending)] + public void Validation_Works(LedgerListByExternalIDParamsEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(LedgerListByExternalIDParamsEntryStatus.Committed)] + [InlineData(LedgerListByExternalIDParamsEntryStatus.Pending)] + public void SerializationRoundtrip_Works(LedgerListByExternalIDParamsEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class LedgerListByExternalIDParamsEntryTypeTest : TestBase +{ + [Theory] + [InlineData(LedgerListByExternalIDParamsEntryType.Increment)] + [InlineData(LedgerListByExternalIDParamsEntryType.Decrement)] + [InlineData(LedgerListByExternalIDParamsEntryType.ExpirationChange)] + [InlineData(LedgerListByExternalIDParamsEntryType.CreditBlockExpiry)] + [InlineData(LedgerListByExternalIDParamsEntryType.Void)] + [InlineData(LedgerListByExternalIDParamsEntryType.VoidInitiated)] + [InlineData(LedgerListByExternalIDParamsEntryType.Amendment)] + public void Validation_Works(LedgerListByExternalIDParamsEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(LedgerListByExternalIDParamsEntryType.Increment)] + [InlineData(LedgerListByExternalIDParamsEntryType.Decrement)] + [InlineData(LedgerListByExternalIDParamsEntryType.ExpirationChange)] + [InlineData(LedgerListByExternalIDParamsEntryType.CreditBlockExpiry)] + [InlineData(LedgerListByExternalIDParamsEntryType.Void)] + [InlineData(LedgerListByExternalIDParamsEntryType.VoidInitiated)] + [InlineData(LedgerListByExternalIDParamsEntryType.Amendment)] + public void SerializationRoundtrip_Works(LedgerListByExternalIDParamsEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDResponseTest.cs new file mode 100644 index 00000000..de7b4ddf --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListByExternalIDResponseTest.cs @@ -0,0 +1,1301 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerListByExternalIDResponseTest : TestBase +{ + [Fact] + public void IncrementLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + value.Validate(); + } + + [Fact] + public void DecrementLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + value.Validate(); + } + + [Fact] + public void ExpirationChangeLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void CreditBlockExpiryLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void VoidLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void VoidInitiatedLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmendmentLedgerEntryValidationWorks() + { + LedgerListByExternalIDResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void IncrementLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DecrementLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ExpirationChangeLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CreditBlockExpiryLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidInitiatedLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmendmentLedgerEntrySerializationRoundtripWorks() + { + LedgerListByExternalIDResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListPageResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListPageResponseTest.cs new file mode 100644 index 00000000..36425abc --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListPageResponseTest.cs @@ -0,0 +1,2481 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LedgerListPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LedgerListPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LedgerListPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new LedgerListPageResponse + { + Data = + [ + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListParamsTest.cs new file mode 100644 index 00000000..200c3b89 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListParamsTest.cs @@ -0,0 +1,288 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new LedgerListParams + { + CustomerID = "customer_id", + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Cursor = "cursor", + EntryStatus = EntryStatus.Committed, + EntryType = EntryType.Increment, + Limit = 1, + MinimumAmount = "minimum_amount", + }; + + string expectedCustomerID = "customer_id"; + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + string expectedCursor = "cursor"; + ApiEnum expectedEntryStatus = EntryStatus.Committed; + ApiEnum expectedEntryType = EntryType.Increment; + long expectedLimit = 1; + string expectedMinimumAmount = "minimum_amount"; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedEntryStatus, parameters.EntryStatus); + Assert.Equal(expectedEntryType, parameters.EntryType); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedMinimumAmount, parameters.MinimumAmount); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new LedgerListParams + { + CustomerID = "customer_id", + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Cursor = "cursor", + EntryStatus = EntryStatus.Committed, + EntryType = EntryType.Increment, + MinimumAmount = "minimum_amount", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new LedgerListParams + { + CustomerID = "customer_id", + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Cursor = "cursor", + EntryStatus = EntryStatus.Committed, + EntryType = EntryType.Increment, + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new LedgerListParams { CustomerID = "customer_id", Limit = 1 }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.EntryStatus); + Assert.False(parameters.RawQueryData.ContainsKey("entry_status")); + Assert.Null(parameters.EntryType); + Assert.False(parameters.RawQueryData.ContainsKey("entry_type")); + Assert.Null(parameters.MinimumAmount); + Assert.False(parameters.RawQueryData.ContainsKey("minimum_amount")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new LedgerListParams + { + CustomerID = "customer_id", + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Currency = null, + Cursor = null, + EntryStatus = null, + EntryType = null, + MinimumAmount = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.EntryStatus); + Assert.False(parameters.RawQueryData.ContainsKey("entry_status")); + Assert.Null(parameters.EntryType); + Assert.False(parameters.RawQueryData.ContainsKey("entry_type")); + Assert.Null(parameters.MinimumAmount); + Assert.False(parameters.RawQueryData.ContainsKey("minimum_amount")); + } +} + +public class EntryStatusTest : TestBase +{ + [Theory] + [InlineData(EntryStatus.Committed)] + [InlineData(EntryStatus.Pending)] + public void Validation_Works(EntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EntryStatus.Committed)] + [InlineData(EntryStatus.Pending)] + public void SerializationRoundtrip_Works(EntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EntryTypeTest : TestBase +{ + [Theory] + [InlineData(EntryType.Increment)] + [InlineData(EntryType.Decrement)] + [InlineData(EntryType.ExpirationChange)] + [InlineData(EntryType.CreditBlockExpiry)] + [InlineData(EntryType.Void)] + [InlineData(EntryType.VoidInitiated)] + [InlineData(EntryType.Amendment)] + public void Validation_Works(EntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EntryType.Increment)] + [InlineData(EntryType.Decrement)] + [InlineData(EntryType.ExpirationChange)] + [InlineData(EntryType.CreditBlockExpiry)] + [InlineData(EntryType.Void)] + [InlineData(EntryType.VoidInitiated)] + [InlineData(EntryType.Amendment)] + public void SerializationRoundtrip_Works(EntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListResponseTest.cs new file mode 100644 index 00000000..6c33648d --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/LedgerListResponseTest.cs @@ -0,0 +1,1301 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers.Credits.Ledger; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class LedgerListResponseTest : TestBase +{ + [Fact] + public void IncrementLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + value.Validate(); + } + + [Fact] + public void DecrementLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + value.Validate(); + } + + [Fact] + public void ExpirationChangeLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void CreditBlockExpiryLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void VoidLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void VoidInitiatedLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmendmentLedgerEntryValidationWorks() + { + LedgerListResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + value.Validate(); + } + + [Fact] + public void IncrementLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new IncrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = IncrementLedgerEntryEntryStatus.Committed, + EntryType = IncrementLedgerEntryEntryType.Increment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DecrementLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new DecrementLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = DecrementLedgerEntryEntryStatus.Committed, + EntryType = DecrementLedgerEntryEntryType.Decrement, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + EventID = "event_id", + InvoiceID = "invoice_id", + PriceID = "price_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ExpirationChangeLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new ExpirationChangeLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = ExpirationChangeLedgerEntryEntryStatus.Committed, + EntryType = ExpirationChangeLedgerEntryEntryType.ExpirationChange, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CreditBlockExpiryLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new CreditBlockExpiryLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = CreditBlockExpiryLedgerEntryEntryStatus.Committed, + EntryType = CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new VoidLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void VoidInitiatedLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new VoidInitiatedLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmendmentLedgerEntrySerializationRoundtripWorks() + { + LedgerListResponse value = new( + new AmendmentLedgerEntry() + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = AmendmentLedgerEntryEntryStatus.Committed, + EntryType = AmendmentLedgerEntryEntryType.Amendment, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryTest.cs new file mode 100644 index 00000000..4fc89d97 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryTest.cs @@ -0,0 +1,413 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class VoidInitiatedLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new VoidInitiatedLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + VoidInitiatedLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + VoidInitiatedLedgerEntryEntryType.VoidInitiated; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + DateTimeOffset expectedNewBlockExpiryDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + double expectedStartingBalance = 0; + double expectedVoidAmount = 0; + string expectedVoidReason = "void_reason"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedNewBlockExpiryDate, model.NewBlockExpiryDate); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedVoidAmount, model.VoidAmount); + Assert.Equal(expectedVoidReason, model.VoidReason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new VoidInitiatedLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new VoidInitiatedLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + VoidInitiatedLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = + VoidInitiatedLedgerEntryEntryType.VoidInitiated; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + DateTimeOffset expectedNewBlockExpiryDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + double expectedStartingBalance = 0; + double expectedVoidAmount = 0; + string expectedVoidReason = "void_reason"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedNewBlockExpiryDate, deserialized.NewBlockExpiryDate); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedVoidAmount, deserialized.VoidAmount); + Assert.Equal(expectedVoidReason, deserialized.VoidReason); + } + + [Fact] + public void Validation_Works() + { + var model = new VoidInitiatedLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidInitiatedLedgerEntryEntryStatus.Committed, + EntryType = VoidInitiatedLedgerEntryEntryType.VoidInitiated, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + NewBlockExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + model.Validate(); + } +} + +public class VoidInitiatedLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(VoidInitiatedLedgerEntryEntryStatus.Committed)] + [InlineData(VoidInitiatedLedgerEntryEntryStatus.Pending)] + public void Validation_Works(VoidInitiatedLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(VoidInitiatedLedgerEntryEntryStatus.Committed)] + [InlineData(VoidInitiatedLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(VoidInitiatedLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class VoidInitiatedLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(VoidInitiatedLedgerEntryEntryType.VoidInitiated)] + public void Validation_Works(VoidInitiatedLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(VoidInitiatedLedgerEntryEntryType.VoidInitiated)] + public void SerializationRoundtrip_Works(VoidInitiatedLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/Ledger/VoidLedgerEntryTest.cs b/src/Orb.Tests/Models/Customers/Credits/Ledger/VoidLedgerEntryTest.cs new file mode 100644 index 00000000..c181ba44 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/Ledger/VoidLedgerEntryTest.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Models.Customers.Credits.Ledger; + +public class VoidLedgerEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new VoidLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + VoidLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = VoidLedgerEntryEntryType.Void; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + double expectedVoidAmount = 0; + string expectedVoidReason = "void_reason"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditBlock, model.CreditBlock); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedEntryStatus, model.EntryStatus); + Assert.Equal(expectedEntryType, model.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, model.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedVoidAmount, model.VoidAmount); + Assert.Equal(expectedVoidReason, model.VoidReason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new VoidLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new VoidLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + double expectedAmount = 0; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + AffectedBlock expectedCreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }; + string expectedCurrency = "currency"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedDescription = "description"; + double expectedEndingBalance = 0; + ApiEnum expectedEntryStatus = + VoidLedgerEntryEntryStatus.Committed; + ApiEnum expectedEntryType = VoidLedgerEntryEntryType.Void; + long expectedLedgerSequenceNumber = 0; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + double expectedStartingBalance = 0; + double expectedVoidAmount = 0; + string expectedVoidReason = "void_reason"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditBlock, deserialized.CreditBlock); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedEntryStatus, deserialized.EntryStatus); + Assert.Equal(expectedEntryType, deserialized.EntryType); + Assert.Equal(expectedLedgerSequenceNumber, deserialized.LedgerSequenceNumber); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedVoidAmount, deserialized.VoidAmount); + Assert.Equal(expectedVoidReason, deserialized.VoidReason); + } + + [Fact] + public void Validation_Works() + { + var model = new VoidLedgerEntry + { + ID = "id", + Amount = 0, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditBlock = new() + { + ID = "id", + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AffectedBlockFilterField.PriceID, + Operator = AffectedBlockFilterOperator.Includes, + Values = ["string"], + }, + ], + PerUnitCostBasis = "per_unit_cost_basis", + }, + Currency = "currency", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + Description = "description", + EndingBalance = 0, + EntryStatus = VoidLedgerEntryEntryStatus.Committed, + EntryType = VoidLedgerEntryEntryType.Void, + LedgerSequenceNumber = 0, + Metadata = new Dictionary() { { "foo", "string" } }, + StartingBalance = 0, + VoidAmount = 0, + VoidReason = "void_reason", + }; + + model.Validate(); + } +} + +public class VoidLedgerEntryEntryStatusTest : TestBase +{ + [Theory] + [InlineData(VoidLedgerEntryEntryStatus.Committed)] + [InlineData(VoidLedgerEntryEntryStatus.Pending)] + public void Validation_Works(VoidLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(VoidLedgerEntryEntryStatus.Committed)] + [InlineData(VoidLedgerEntryEntryStatus.Pending)] + public void SerializationRoundtrip_Works(VoidLedgerEntryEntryStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class VoidLedgerEntryEntryTypeTest : TestBase +{ + [Theory] + [InlineData(VoidLedgerEntryEntryType.Void)] + public void Validation_Works(VoidLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(VoidLedgerEntryEntryType.Void)] + public void SerializationRoundtrip_Works(VoidLedgerEntryEntryType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsTest.cs new file mode 100644 index 00000000..820fdec1 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsTest.cs @@ -0,0 +1,382 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpCreateByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new TopUpCreateByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ActiveFrom = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateByExternalIDParamsExpiresAfterUnit.Day, + }; + + string expectedExternalCustomerID = "external_customer_id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpCreateByExternalIDParamsInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + DateTimeOffset expectedActiveFrom = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpCreateByExternalIDParamsExpiresAfterUnit.Day; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedAmount, parameters.Amount); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedInvoiceSettings, parameters.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, parameters.PerUnitCostBasis); + Assert.Equal(expectedThreshold, parameters.Threshold); + Assert.Equal(expectedActiveFrom, parameters.ActiveFrom); + Assert.Equal(expectedExpiresAfter, parameters.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, parameters.ExpiresAfterUnit); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new TopUpCreateByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + Assert.Null(parameters.ActiveFrom); + Assert.False(parameters.RawBodyData.ContainsKey("active_from")); + Assert.Null(parameters.ExpiresAfter); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after")); + Assert.Null(parameters.ExpiresAfterUnit); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new TopUpCreateByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ActiveFrom = null, + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + Assert.Null(parameters.ActiveFrom); + Assert.False(parameters.RawBodyData.ContainsKey("active_from")); + Assert.Null(parameters.ExpiresAfter); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after")); + Assert.Null(parameters.ExpiresAfterUnit); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after_unit")); + } +} + +public class TopUpCreateByExternalIDParamsInvoiceSettingsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + bool expectedAutoCollection = true; + long expectedNetTerms = 0; + string expectedMemo = "memo"; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedRequireSuccessfulPayment, model.RequireSuccessfulPayment); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedAutoCollection = true; + long expectedNetTerms = 0; + string expectedMemo = "memo"; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedRequireSuccessfulPayment, deserialized.RequireSuccessfulPayment); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + Assert.Null(model.Memo); + Assert.False(model.RawData.ContainsKey("memo")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + + Memo = null, + }; + + Assert.Null(model.Memo); + Assert.True(model.RawData.ContainsKey("memo")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpCreateByExternalIDParamsInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + + Memo = null, + }; + + model.Validate(); + } +} + +public class TopUpCreateByExternalIDParamsExpiresAfterUnitTest : TestBase +{ + [Theory] + [InlineData(TopUpCreateByExternalIDParamsExpiresAfterUnit.Day)] + [InlineData(TopUpCreateByExternalIDParamsExpiresAfterUnit.Month)] + public void Validation_Works(TopUpCreateByExternalIDParamsExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TopUpCreateByExternalIDParamsExpiresAfterUnit.Day)] + [InlineData(TopUpCreateByExternalIDParamsExpiresAfterUnit.Month)] + public void SerializationRoundtrip_Works(TopUpCreateByExternalIDParamsExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponseTest.cs new file mode 100644 index 00000000..35381fa4 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponseTest.cs @@ -0,0 +1,320 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpCreateByExternalIDResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateByExternalIDResponseExpiresAfterUnit.Day, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpCreateByExternalIDResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedInvoiceSettings, model.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedExpiresAfter, model.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, model.ExpiresAfterUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateByExternalIDResponseExpiresAfterUnit.Day, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateByExternalIDResponseExpiresAfterUnit.Day, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpCreateByExternalIDResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedInvoiceSettings, deserialized.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedExpiresAfter, deserialized.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, deserialized.ExpiresAfterUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateByExternalIDResponseExpiresAfterUnit.Day, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + Assert.Null(model.ExpiresAfter); + Assert.False(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.False(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + Assert.Null(model.ExpiresAfter); + Assert.True(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.True(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpCreateByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + model.Validate(); + } +} + +public class TopUpCreateByExternalIDResponseExpiresAfterUnitTest : TestBase +{ + [Theory] + [InlineData(TopUpCreateByExternalIDResponseExpiresAfterUnit.Day)] + [InlineData(TopUpCreateByExternalIDResponseExpiresAfterUnit.Month)] + public void Validation_Works(TopUpCreateByExternalIDResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TopUpCreateByExternalIDResponseExpiresAfterUnit.Day)] + [InlineData(TopUpCreateByExternalIDResponseExpiresAfterUnit.Month)] + public void SerializationRoundtrip_Works( + TopUpCreateByExternalIDResponseExpiresAfterUnit rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateParamsTest.cs new file mode 100644 index 00000000..ab1160a2 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateParamsTest.cs @@ -0,0 +1,375 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new TopUpCreateParams + { + CustomerID = "customer_id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ActiveFrom = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiresAfter = 0, + ExpiresAfterUnit = ExpiresAfterUnit.Day, + }; + + string expectedCustomerID = "customer_id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + InvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + DateTimeOffset expectedActiveFrom = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = ExpiresAfterUnit.Day; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedAmount, parameters.Amount); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedInvoiceSettings, parameters.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, parameters.PerUnitCostBasis); + Assert.Equal(expectedThreshold, parameters.Threshold); + Assert.Equal(expectedActiveFrom, parameters.ActiveFrom); + Assert.Equal(expectedExpiresAfter, parameters.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, parameters.ExpiresAfterUnit); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new TopUpCreateParams + { + CustomerID = "customer_id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + Assert.Null(parameters.ActiveFrom); + Assert.False(parameters.RawBodyData.ContainsKey("active_from")); + Assert.Null(parameters.ExpiresAfter); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after")); + Assert.Null(parameters.ExpiresAfterUnit); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new TopUpCreateParams + { + CustomerID = "customer_id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ActiveFrom = null, + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + Assert.Null(parameters.ActiveFrom); + Assert.False(parameters.RawBodyData.ContainsKey("active_from")); + Assert.Null(parameters.ExpiresAfter); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after")); + Assert.Null(parameters.ExpiresAfterUnit); + Assert.False(parameters.RawBodyData.ContainsKey("expires_after_unit")); + } +} + +public class InvoiceSettingsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + bool expectedAutoCollection = true; + long expectedNetTerms = 0; + string expectedMemo = "memo"; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedRequireSuccessfulPayment, model.RequireSuccessfulPayment); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedAutoCollection = true; + long expectedNetTerms = 0; + string expectedMemo = "memo"; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedRequireSuccessfulPayment, deserialized.RequireSuccessfulPayment); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + Assert.Null(model.Memo); + Assert.False(model.RawData.ContainsKey("memo")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + + Memo = null, + }; + + Assert.Null(model.Memo); + Assert.True(model.RawData.ContainsKey("memo")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new InvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + + Memo = null, + }; + + model.Validate(); + } +} + +public class ExpiresAfterUnitTest : TestBase +{ + [Theory] + [InlineData(ExpiresAfterUnit.Day)] + [InlineData(ExpiresAfterUnit.Month)] + public void Validation_Works(ExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ExpiresAfterUnit.Day)] + [InlineData(ExpiresAfterUnit.Month)] + public void SerializationRoundtrip_Works(ExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateResponseTest.cs new file mode 100644 index 00000000..3968858f --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpCreateResponseTest.cs @@ -0,0 +1,318 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpCreateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateResponseExpiresAfterUnit.Day, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpCreateResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedInvoiceSettings, model.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedExpiresAfter, model.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, model.ExpiresAfterUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateResponseExpiresAfterUnit.Day, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateResponseExpiresAfterUnit.Day, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpCreateResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedInvoiceSettings, deserialized.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedExpiresAfter, deserialized.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, deserialized.ExpiresAfterUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpCreateResponseExpiresAfterUnit.Day, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + Assert.Null(model.ExpiresAfter); + Assert.False(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.False(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + Assert.Null(model.ExpiresAfter); + Assert.True(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.True(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpCreateResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + model.Validate(); + } +} + +public class TopUpCreateResponseExpiresAfterUnitTest : TestBase +{ + [Theory] + [InlineData(TopUpCreateResponseExpiresAfterUnit.Day)] + [InlineData(TopUpCreateResponseExpiresAfterUnit.Month)] + public void Validation_Works(TopUpCreateResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TopUpCreateResponseExpiresAfterUnit.Day)] + [InlineData(TopUpCreateResponseExpiresAfterUnit.Month)] + public void SerializationRoundtrip_Works(TopUpCreateResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParamsTest.cs new file mode 100644 index 00000000..b14a5cf5 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParamsTest.cs @@ -0,0 +1,22 @@ +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpDeleteByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new TopUpDeleteByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + TopUpID = "top_up_id", + }; + + string expectedExternalCustomerID = "external_customer_id"; + string expectedTopUpID = "top_up_id"; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedTopUpID, parameters.TopUpID); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpDeleteParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpDeleteParamsTest.cs new file mode 100644 index 00000000..f9e69f2e --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpDeleteParamsTest.cs @@ -0,0 +1,22 @@ +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpDeleteParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new TopUpDeleteParams + { + CustomerID = "customer_id", + TopUpID = "top_up_id", + }; + + string expectedCustomerID = "customer_id"; + string expectedTopUpID = "top_up_id"; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedTopUpID, parameters.TopUpID); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpInvoiceSettingsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpInvoiceSettingsTest.cs new file mode 100644 index 00000000..7e1ce164 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpInvoiceSettingsTest.cs @@ -0,0 +1,204 @@ +using System.Text.Json; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpInvoiceSettingsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + bool expectedAutoCollection = true; + long expectedNetTerms = 0; + string expectedMemo = "memo"; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedRequireSuccessfulPayment, model.RequireSuccessfulPayment); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedAutoCollection = true; + long expectedNetTerms = 0; + string expectedMemo = "memo"; + bool expectedRequireSuccessfulPayment = true; + + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedRequireSuccessfulPayment, deserialized.RequireSuccessfulPayment); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + Assert.Null(model.RequireSuccessfulPayment); + Assert.False(model.RawData.ContainsKey("require_successful_payment")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + + // Null should be interpreted as omitted for these properties + RequireSuccessfulPayment = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + Assert.Null(model.Memo); + Assert.False(model.RawData.ContainsKey("memo")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + + Memo = null, + }; + + Assert.Null(model.Memo); + Assert.True(model.RawData.ContainsKey("memo")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpInvoiceSettings + { + AutoCollection = true, + NetTerms = 0, + RequireSuccessfulPayment = true, + + Memo = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseTest.cs new file mode 100644 index 00000000..a3e5695e --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseTest.cs @@ -0,0 +1,202 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpListByExternalIDPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpListByExternalIDPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDParamsTest.cs new file mode 100644 index 00000000..254b0d39 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDParamsTest.cs @@ -0,0 +1,82 @@ +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpListByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new TopUpListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Cursor = "cursor", + Limit = 1, + }; + + string expectedExternalCustomerID = "external_customer_id"; + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new TopUpListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Cursor = "cursor", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new TopUpListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new TopUpListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Limit = 1, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new TopUpListByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDResponseTest.cs new file mode 100644 index 00000000..7c20d976 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListByExternalIDResponseTest.cs @@ -0,0 +1,318 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpListByExternalIDResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpListByExternalIDResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedInvoiceSettings, model.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedExpiresAfter, model.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, model.ExpiresAfterUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpListByExternalIDResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedInvoiceSettings, deserialized.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedExpiresAfter, deserialized.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, deserialized.ExpiresAfterUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListByExternalIDResponseExpiresAfterUnit.Day, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + Assert.Null(model.ExpiresAfter); + Assert.False(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.False(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + Assert.Null(model.ExpiresAfter); + Assert.True(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.True(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpListByExternalIDResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + model.Validate(); + } +} + +public class TopUpListByExternalIDResponseExpiresAfterUnitTest : TestBase +{ + [Theory] + [InlineData(TopUpListByExternalIDResponseExpiresAfterUnit.Day)] + [InlineData(TopUpListByExternalIDResponseExpiresAfterUnit.Month)] + public void Validation_Works(TopUpListByExternalIDResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TopUpListByExternalIDResponseExpiresAfterUnit.Day)] + [InlineData(TopUpListByExternalIDResponseExpiresAfterUnit.Month)] + public void SerializationRoundtrip_Works(TopUpListByExternalIDResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListPageResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListPageResponseTest.cs new file mode 100644 index 00000000..8c00ee90 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListPageResponseTest.cs @@ -0,0 +1,202 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpListPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpListPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpListPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpListPageResponse + { + Data = + [ + new() + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListParamsTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListParamsTest.cs new file mode 100644 index 00000000..8dd2b562 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListParamsTest.cs @@ -0,0 +1,74 @@ +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new TopUpListParams + { + CustomerID = "customer_id", + Cursor = "cursor", + Limit = 1, + }; + + string expectedCustomerID = "customer_id"; + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new TopUpListParams { CustomerID = "customer_id", Cursor = "cursor" }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new TopUpListParams + { + CustomerID = "customer_id", + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new TopUpListParams { CustomerID = "customer_id", Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new TopUpListParams + { + CustomerID = "customer_id", + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListResponseTest.cs b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListResponseTest.cs new file mode 100644 index 00000000..096a8302 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/Credits/TopUps/TopUpListResponseTest.cs @@ -0,0 +1,314 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Tests.Models.Customers.Credits.TopUps; + +public class TopUpListResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpListResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedInvoiceSettings, model.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedExpiresAfter, model.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, model.ExpiresAfterUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedCurrency = "currency"; + TopUpInvoiceSettings expectedInvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + string expectedThreshold = "threshold"; + long expectedExpiresAfter = 0; + ApiEnum expectedExpiresAfterUnit = + TopUpListResponseExpiresAfterUnit.Day; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedInvoiceSettings, deserialized.InvoiceSettings); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedExpiresAfter, deserialized.ExpiresAfter); + Assert.Equal(expectedExpiresAfterUnit, deserialized.ExpiresAfterUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + ExpiresAfter = 0, + ExpiresAfterUnit = TopUpListResponseExpiresAfterUnit.Day, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + Assert.Null(model.ExpiresAfter); + Assert.False(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.False(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + Assert.Null(model.ExpiresAfter); + Assert.True(model.RawData.ContainsKey("expires_after")); + Assert.Null(model.ExpiresAfterUnit); + Assert.True(model.RawData.ContainsKey("expires_after_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TopUpListResponse + { + ID = "id", + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + + ExpiresAfter = null, + ExpiresAfterUnit = null, + }; + + model.Validate(); + } +} + +public class TopUpListResponseExpiresAfterUnitTest : TestBase +{ + [Theory] + [InlineData(TopUpListResponseExpiresAfterUnit.Day)] + [InlineData(TopUpListResponseExpiresAfterUnit.Month)] + public void Validation_Works(TopUpListResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TopUpListResponseExpiresAfterUnit.Day)] + [InlineData(TopUpListResponseExpiresAfterUnit.Month)] + public void SerializationRoundtrip_Works(TopUpListResponseExpiresAfterUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerCreateParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerCreateParamsTest.cs new file mode 100644 index 00000000..06e345a8 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerCreateParamsTest.cs @@ -0,0 +1,1154 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Customers; + +public class CustomerCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerCreateParams + { + Email = "dev@stainless.com", + Name = "x", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }, + AdditionalEmails = ["dev@stainless.com"], + AutoCollection = true, + AutoIssuance = true, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Currency = "currency", + EmailDelivery = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + PaymentProvider = CustomerCreateParamsPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + ReportingConfiguration = new(true), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxConfiguration = new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + }; + + string expectedEmail = "dev@stainless.com"; + string expectedName = "x"; + NewAccountingSyncConfiguration expectedAccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + List expectedAdditionalEmails = ["dev@stainless.com"]; + bool expectedAutoCollection = true; + bool expectedAutoIssuance = true; + AddressInput expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + string expectedCurrency = "currency"; + bool expectedEmailDelivery = true; + string expectedExternalCustomerID = "external_customer_id"; + CustomerHierarchyConfig expectedHierarchy = new() + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + PaymentConfiguration expectedPaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + ApiEnum expectedPaymentProvider = + CustomerCreateParamsPaymentProvider.Quickbooks; + string expectedPaymentProviderID = "payment_provider_id"; + NewReportingConfiguration expectedReportingConfiguration = new(true); + AddressInput expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + TaxConfiguration expectedTaxConfiguration = new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + Models::CustomerTaxID expectedTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }; + string expectedTimezone = "timezone"; + + Assert.Equal(expectedEmail, parameters.Email); + Assert.Equal(expectedName, parameters.Name); + Assert.Equal(expectedAccountingSyncConfiguration, parameters.AccountingSyncConfiguration); + Assert.NotNull(parameters.AdditionalEmails); + Assert.Equal(expectedAdditionalEmails.Count, parameters.AdditionalEmails.Count); + for (int i = 0; i < expectedAdditionalEmails.Count; i++) + { + Assert.Equal(expectedAdditionalEmails[i], parameters.AdditionalEmails[i]); + } + Assert.Equal(expectedAutoCollection, parameters.AutoCollection); + Assert.Equal(expectedAutoIssuance, parameters.AutoIssuance); + Assert.Equal(expectedBillingAddress, parameters.BillingAddress); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedEmailDelivery, parameters.EmailDelivery); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedHierarchy, parameters.Hierarchy); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedPaymentConfiguration, parameters.PaymentConfiguration); + Assert.Equal(expectedPaymentProvider, parameters.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, parameters.PaymentProviderID); + Assert.Equal(expectedReportingConfiguration, parameters.ReportingConfiguration); + Assert.Equal(expectedShippingAddress, parameters.ShippingAddress); + Assert.Equal(expectedTaxConfiguration, parameters.TaxConfiguration); + Assert.Equal(expectedTaxID, parameters.TaxID); + Assert.Equal(expectedTimezone, parameters.Timezone); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CustomerCreateParams { Email = "dev@stainless.com", Name = "x" }; + + Assert.Null(parameters.AccountingSyncConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("accounting_sync_configuration")); + Assert.Null(parameters.AdditionalEmails); + Assert.False(parameters.RawBodyData.ContainsKey("additional_emails")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AutoIssuance); + Assert.False(parameters.RawBodyData.ContainsKey("auto_issuance")); + Assert.Null(parameters.BillingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("billing_address")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.EmailDelivery); + Assert.False(parameters.RawBodyData.ContainsKey("email_delivery")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Hierarchy); + Assert.False(parameters.RawBodyData.ContainsKey("hierarchy")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.PaymentConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("payment_configuration")); + Assert.Null(parameters.PaymentProvider); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider")); + Assert.Null(parameters.PaymentProviderID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider_id")); + Assert.Null(parameters.ReportingConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("reporting_configuration")); + Assert.Null(parameters.ShippingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("shipping_address")); + Assert.Null(parameters.TaxConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("tax_configuration")); + Assert.Null(parameters.TaxID); + Assert.False(parameters.RawBodyData.ContainsKey("tax_id")); + Assert.Null(parameters.Timezone); + Assert.False(parameters.RawBodyData.ContainsKey("timezone")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CustomerCreateParams + { + Email = "dev@stainless.com", + Name = "x", + + AccountingSyncConfiguration = null, + AdditionalEmails = null, + AutoCollection = null, + AutoIssuance = null, + BillingAddress = null, + Currency = null, + EmailDelivery = null, + ExternalCustomerID = null, + Hierarchy = null, + Metadata = null, + PaymentConfiguration = null, + PaymentProvider = null, + PaymentProviderID = null, + ReportingConfiguration = null, + ShippingAddress = null, + TaxConfiguration = null, + TaxID = null, + Timezone = null, + }; + + Assert.Null(parameters.AccountingSyncConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("accounting_sync_configuration")); + Assert.Null(parameters.AdditionalEmails); + Assert.False(parameters.RawBodyData.ContainsKey("additional_emails")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AutoIssuance); + Assert.False(parameters.RawBodyData.ContainsKey("auto_issuance")); + Assert.Null(parameters.BillingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("billing_address")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.EmailDelivery); + Assert.False(parameters.RawBodyData.ContainsKey("email_delivery")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Hierarchy); + Assert.False(parameters.RawBodyData.ContainsKey("hierarchy")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.PaymentConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("payment_configuration")); + Assert.Null(parameters.PaymentProvider); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider")); + Assert.Null(parameters.PaymentProviderID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider_id")); + Assert.Null(parameters.ReportingConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("reporting_configuration")); + Assert.Null(parameters.ShippingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("shipping_address")); + Assert.Null(parameters.TaxConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("tax_configuration")); + Assert.Null(parameters.TaxID); + Assert.False(parameters.RawBodyData.ContainsKey("tax_id")); + Assert.Null(parameters.Timezone); + Assert.False(parameters.RawBodyData.ContainsKey("timezone")); + } +} + +public class PaymentConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + List expectedPaymentProviders = + [ + new() { ProviderType = ProviderType.Stripe, ExcludedPaymentMethodTypes = ["string"] }, + ]; + + Assert.NotNull(model.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, model.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], model.PaymentProviders[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedPaymentProviders = + [ + new() { ProviderType = ProviderType.Stripe, ExcludedPaymentMethodTypes = ["string"] }, + ]; + + Assert.NotNull(deserialized.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, deserialized.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], deserialized.PaymentProviders[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PaymentConfiguration { }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new PaymentConfiguration { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new PaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new PaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + model.Validate(); + } +} + +public class PaymentProviderTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PaymentProvider + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + ApiEnum expectedProviderType = ProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, model.ProviderType); + Assert.NotNull(model.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + model.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + model.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PaymentProvider + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PaymentProvider + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedProviderType = ProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, deserialized.ProviderType); + Assert.NotNull(deserialized.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + deserialized.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + deserialized.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PaymentProvider + { + ProviderType = ProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PaymentProvider { ProviderType = ProviderType.Stripe }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new PaymentProvider { ProviderType = ProviderType.Stripe }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new PaymentProvider + { + ProviderType = ProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new PaymentProvider + { + ProviderType = ProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + model.Validate(); + } +} + +public class ProviderTypeTest : TestBase +{ + [Theory] + [InlineData(ProviderType.Stripe)] + public void Validation_Works(ProviderType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ProviderType.Stripe)] + public void SerializationRoundtrip_Works(ProviderType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerCreateParamsPaymentProviderTest : TestBase +{ + [Theory] + [InlineData(CustomerCreateParamsPaymentProvider.Quickbooks)] + [InlineData(CustomerCreateParamsPaymentProvider.BillCom)] + [InlineData(CustomerCreateParamsPaymentProvider.StripeCharge)] + [InlineData(CustomerCreateParamsPaymentProvider.StripeInvoice)] + [InlineData(CustomerCreateParamsPaymentProvider.Netsuite)] + public void Validation_Works(CustomerCreateParamsPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerCreateParamsPaymentProvider.Quickbooks)] + [InlineData(CustomerCreateParamsPaymentProvider.BillCom)] + [InlineData(CustomerCreateParamsPaymentProvider.StripeCharge)] + [InlineData(CustomerCreateParamsPaymentProvider.StripeInvoice)] + [InlineData(CustomerCreateParamsPaymentProvider.Netsuite)] + public void SerializationRoundtrip_Works(CustomerCreateParamsPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TaxConfigurationTest : TestBase +{ + [Fact] + public void NewAvalaraValidationWorks() + { + TaxConfiguration value = new( + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + } + ); + value.Validate(); + } + + [Fact] + public void NewTaxJarValidationWorks() + { + TaxConfiguration value = new( + new NewTaxJarConfiguration() + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NewSphereValidationWorks() + { + TaxConfiguration value = new( + new NewSphereConfiguration() + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NumeralValidationWorks() + { + TaxConfiguration value = new( + new Numeral() { TaxExempt = true, AutomaticTaxEnabled = true } + ); + value.Validate(); + } + + [Fact] + public void AnrokValidationWorks() + { + TaxConfiguration value = new(new Anrok() { TaxExempt = true, AutomaticTaxEnabled = true }); + value.Validate(); + } + + [Fact] + public void StripeValidationWorks() + { + TaxConfiguration value = new(new Stripe() { TaxExempt = true, AutomaticTaxEnabled = true }); + value.Validate(); + } + + [Fact] + public void NewAvalaraSerializationRoundtripWorks() + { + TaxConfiguration value = new( + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewTaxJarSerializationRoundtripWorks() + { + TaxConfiguration value = new( + new NewTaxJarConfiguration() + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSphereSerializationRoundtripWorks() + { + TaxConfiguration value = new( + new NewSphereConfiguration() + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NumeralSerializationRoundtripWorks() + { + TaxConfiguration value = new( + new Numeral() { TaxExempt = true, AutomaticTaxEnabled = true } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AnrokSerializationRoundtripWorks() + { + TaxConfiguration value = new(new Anrok() { TaxExempt = true, AutomaticTaxEnabled = true }); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void StripeSerializationRoundtripWorks() + { + TaxConfiguration value = new(new Stripe() { TaxExempt = true, AutomaticTaxEnabled = true }); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class NumeralTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Numeral { TaxExempt = true, AutomaticTaxEnabled = true }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"numeral\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Numeral { TaxExempt = true, AutomaticTaxEnabled = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Numeral { TaxExempt = true, AutomaticTaxEnabled = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"numeral\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new Numeral { TaxExempt = true, AutomaticTaxEnabled = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Numeral { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Numeral { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Numeral + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Numeral + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class AnrokTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Anrok { TaxExempt = true, AutomaticTaxEnabled = true }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"anrok\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Anrok { TaxExempt = true, AutomaticTaxEnabled = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Anrok { TaxExempt = true, AutomaticTaxEnabled = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"anrok\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new Anrok { TaxExempt = true, AutomaticTaxEnabled = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Anrok { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Anrok { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Anrok + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Anrok + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class StripeTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Stripe { TaxExempt = true, AutomaticTaxEnabled = true }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"stripe\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Stripe { TaxExempt = true, AutomaticTaxEnabled = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Stripe { TaxExempt = true, AutomaticTaxEnabled = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"stripe\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new Stripe { TaxExempt = true, AutomaticTaxEnabled = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Stripe { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Stripe { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Stripe + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Stripe + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerDeleteParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerDeleteParamsTest.cs new file mode 100644 index 00000000..8fb72f27 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerDeleteParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerDeleteParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerDeleteParams { CustomerID = "customer_id" }; + + string expectedCustomerID = "customer_id"; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerFetchByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerFetchByExternalIDParamsTest.cs new file mode 100644 index 00000000..2880ca31 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerFetchByExternalIDParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerFetchByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerFetchByExternalIDParams + { + ExternalCustomerID = "external_customer_id", + }; + + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerFetchParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerFetchParamsTest.cs new file mode 100644 index 00000000..9d8f9e12 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerFetchParams { CustomerID = "customer_id" }; + + string expectedCustomerID = "customer_id"; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerHierarchyConfigTest.cs b/src/Orb.Tests/Models/Customers/CustomerHierarchyConfigTest.cs new file mode 100644 index 00000000..1c0ab347 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerHierarchyConfigTest.cs @@ -0,0 +1,171 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerHierarchyConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerHierarchyConfig + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + + List expectedChildCustomerIDs = ["string"]; + string expectedParentCustomerID = "parent_customer_id"; + + Assert.NotNull(model.ChildCustomerIDs); + Assert.Equal(expectedChildCustomerIDs.Count, model.ChildCustomerIDs.Count); + for (int i = 0; i < expectedChildCustomerIDs.Count; i++) + { + Assert.Equal(expectedChildCustomerIDs[i], model.ChildCustomerIDs[i]); + } + Assert.Equal(expectedParentCustomerID, model.ParentCustomerID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerHierarchyConfig + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerHierarchyConfig + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedChildCustomerIDs = ["string"]; + string expectedParentCustomerID = "parent_customer_id"; + + Assert.NotNull(deserialized.ChildCustomerIDs); + Assert.Equal(expectedChildCustomerIDs.Count, deserialized.ChildCustomerIDs.Count); + for (int i = 0; i < expectedChildCustomerIDs.Count; i++) + { + Assert.Equal(expectedChildCustomerIDs[i], deserialized.ChildCustomerIDs[i]); + } + Assert.Equal(expectedParentCustomerID, deserialized.ParentCustomerID); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerHierarchyConfig + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerHierarchyConfig { ParentCustomerID = "parent_customer_id" }; + + Assert.Null(model.ChildCustomerIDs); + Assert.False(model.RawData.ContainsKey("child_customer_ids")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerHierarchyConfig { ParentCustomerID = "parent_customer_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerHierarchyConfig + { + ParentCustomerID = "parent_customer_id", + + // Null should be interpreted as omitted for these properties + ChildCustomerIDs = null, + }; + + Assert.Null(model.ChildCustomerIDs); + Assert.False(model.RawData.ContainsKey("child_customer_ids")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerHierarchyConfig + { + ParentCustomerID = "parent_customer_id", + + // Null should be interpreted as omitted for these properties + ChildCustomerIDs = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerHierarchyConfig { ChildCustomerIDs = ["string"] }; + + Assert.Null(model.ParentCustomerID); + Assert.False(model.RawData.ContainsKey("parent_customer_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerHierarchyConfig { ChildCustomerIDs = ["string"] }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerHierarchyConfig + { + ChildCustomerIDs = ["string"], + + ParentCustomerID = null, + }; + + Assert.Null(model.ParentCustomerID); + Assert.True(model.RawData.ContainsKey("parent_customer_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerHierarchyConfig + { + ChildCustomerIDs = ["string"], + + ParentCustomerID = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerListPageResponseTest.cs b/src/Orb.Tests/Models/Customers/CustomerListPageResponseTest.cs new file mode 100644 index 00000000..b5d8752d --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerListPageResponseTest.cs @@ -0,0 +1,563 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerListPageResponse + { + Data = + [ + new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerListPageResponse + { + Data = + [ + new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerListPageResponse + { + Data = + [ + new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerListPageResponse + { + Data = + [ + new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerListParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerListParamsTest.cs new file mode 100644 index 00000000..6e604ca5 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerListParamsTest.cs @@ -0,0 +1,113 @@ +using System; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + Limit = 1, + }; + + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CustomerListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new CustomerListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CustomerListParams { Limit = 1 }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CustomerListParams + { + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Cursor = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParamsTest.cs new file mode 100644 index 00000000..5fec308e --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams + { + ExternalCustomerID = "external_customer_id", + }; + + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParamsTest.cs new file mode 100644 index 00000000..f23dbc97 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerSyncPaymentMethodsFromGatewayParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerSyncPaymentMethodsFromGatewayParams + { + CustomerID = "customer_id", + }; + + string expectedCustomerID = "customer_id"; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerTest.cs b/src/Orb.Tests/Models/Customers/CustomerTest.cs new file mode 100644 index 00000000..9070273f --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerTest.cs @@ -0,0 +1,1609 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + + string expectedID = "id"; + List expectedAdditionalEmails = ["string"]; + bool expectedAutoCollection = true; + bool expectedAutoIssuance = true; + string expectedBalance = "balance"; + Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + string expectedEmail = "email"; + bool expectedEmailDelivery = true; + bool expectedExemptFromAutomatedTax = true; + string expectedExternalCustomerID = "external_customer_id"; + Hierarchy expectedHierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + ApiEnum expectedPaymentProvider = + CustomerPaymentProvider.Quickbooks; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedPortalURL = "portal_url"; + Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + CustomerTaxID expectedTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + string expectedTimezone = "timezone"; + AccountingSyncConfiguration expectedAccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }; + bool expectedAutomaticTaxEnabled = true; + CustomerPaymentConfiguration expectedPaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + ReportingConfiguration expectedReportingConfiguration = new(true); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdditionalEmails.Count, model.AdditionalEmails.Count); + for (int i = 0; i < expectedAdditionalEmails.Count; i++) + { + Assert.Equal(expectedAdditionalEmails[i], model.AdditionalEmails[i]); + } + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedAutoIssuance, model.AutoIssuance); + Assert.Equal(expectedBalance, model.Balance); + Assert.Equal(expectedBillingAddress, model.BillingAddress); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedEmail, model.Email); + Assert.Equal(expectedEmailDelivery, model.EmailDelivery); + Assert.Equal(expectedExemptFromAutomatedTax, model.ExemptFromAutomatedTax); + Assert.Equal(expectedExternalCustomerID, model.ExternalCustomerID); + Assert.Equal(expectedHierarchy, model.Hierarchy); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPaymentProvider, model.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, model.PaymentProviderID); + Assert.Equal(expectedPortalURL, model.PortalURL); + Assert.Equal(expectedShippingAddress, model.ShippingAddress); + Assert.Equal(expectedTaxID, model.TaxID); + Assert.Equal(expectedTimezone, model.Timezone); + Assert.Equal(expectedAccountingSyncConfiguration, model.AccountingSyncConfiguration); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + Assert.Equal(expectedPaymentConfiguration, model.PaymentConfiguration); + Assert.Equal(expectedReportingConfiguration, model.ReportingConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + List expectedAdditionalEmails = ["string"]; + bool expectedAutoCollection = true; + bool expectedAutoIssuance = true; + string expectedBalance = "balance"; + Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + string expectedEmail = "email"; + bool expectedEmailDelivery = true; + bool expectedExemptFromAutomatedTax = true; + string expectedExternalCustomerID = "external_customer_id"; + Hierarchy expectedHierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + ApiEnum expectedPaymentProvider = + CustomerPaymentProvider.Quickbooks; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedPortalURL = "portal_url"; + Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + CustomerTaxID expectedTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + string expectedTimezone = "timezone"; + AccountingSyncConfiguration expectedAccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }; + bool expectedAutomaticTaxEnabled = true; + CustomerPaymentConfiguration expectedPaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + ReportingConfiguration expectedReportingConfiguration = new(true); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdditionalEmails.Count, deserialized.AdditionalEmails.Count); + for (int i = 0; i < expectedAdditionalEmails.Count; i++) + { + Assert.Equal(expectedAdditionalEmails[i], deserialized.AdditionalEmails[i]); + } + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedAutoIssuance, deserialized.AutoIssuance); + Assert.Equal(expectedBalance, deserialized.Balance); + Assert.Equal(expectedBillingAddress, deserialized.BillingAddress); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedEmail, deserialized.Email); + Assert.Equal(expectedEmailDelivery, deserialized.EmailDelivery); + Assert.Equal(expectedExemptFromAutomatedTax, deserialized.ExemptFromAutomatedTax); + Assert.Equal(expectedExternalCustomerID, deserialized.ExternalCustomerID); + Assert.Equal(expectedHierarchy, deserialized.Hierarchy); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPaymentProvider, deserialized.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, deserialized.PaymentProviderID); + Assert.Equal(expectedPortalURL, deserialized.PortalURL); + Assert.Equal(expectedShippingAddress, deserialized.ShippingAddress); + Assert.Equal(expectedTaxID, deserialized.TaxID); + Assert.Equal(expectedTimezone, deserialized.Timezone); + Assert.Equal(expectedAccountingSyncConfiguration, deserialized.AccountingSyncConfiguration); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + Assert.Equal(expectedPaymentConfiguration, deserialized.PaymentConfiguration); + Assert.Equal(expectedReportingConfiguration, deserialized.ReportingConfiguration); + } + + [Fact] + public void Validation_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + }; + + Assert.Null(model.AccountingSyncConfiguration); + Assert.False(model.RawData.ContainsKey("accounting_sync_configuration")); + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + Assert.Null(model.PaymentConfiguration); + Assert.False(model.RawData.ContainsKey("payment_configuration")); + Assert.Null(model.ReportingConfiguration); + Assert.False(model.RawData.ContainsKey("reporting_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + + AccountingSyncConfiguration = null, + AutomaticTaxEnabled = null, + PaymentConfiguration = null, + ReportingConfiguration = null, + }; + + Assert.Null(model.AccountingSyncConfiguration); + Assert.True(model.RawData.ContainsKey("accounting_sync_configuration")); + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + Assert.Null(model.PaymentConfiguration); + Assert.True(model.RawData.ContainsKey("payment_configuration")); + Assert.Null(model.ReportingConfiguration); + Assert.True(model.RawData.ContainsKey("reporting_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Customer + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + + AccountingSyncConfiguration = null, + AutomaticTaxEnabled = null, + PaymentConfiguration = null, + ReportingConfiguration = null, + }; + + model.Validate(); + } +} + +public class HierarchyTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Hierarchy + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }; + + List expectedChildren = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ]; + CustomerMinified expectedParent = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + + Assert.Equal(expectedChildren.Count, model.Children.Count); + for (int i = 0; i < expectedChildren.Count; i++) + { + Assert.Equal(expectedChildren[i], model.Children[i]); + } + Assert.Equal(expectedParent, model.Parent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Hierarchy + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Hierarchy + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedChildren = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ]; + CustomerMinified expectedParent = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + + Assert.Equal(expectedChildren.Count, deserialized.Children.Count); + for (int i = 0; i < expectedChildren.Count; i++) + { + Assert.Equal(expectedChildren[i], deserialized.Children[i]); + } + Assert.Equal(expectedParent, deserialized.Parent); + } + + [Fact] + public void Validation_Works() + { + var model = new Hierarchy + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }; + + model.Validate(); + } +} + +public class CustomerPaymentProviderTest : TestBase +{ + [Theory] + [InlineData(CustomerPaymentProvider.Quickbooks)] + [InlineData(CustomerPaymentProvider.BillCom)] + [InlineData(CustomerPaymentProvider.StripeCharge)] + [InlineData(CustomerPaymentProvider.StripeInvoice)] + [InlineData(CustomerPaymentProvider.Netsuite)] + public void Validation_Works(CustomerPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerPaymentProvider.Quickbooks)] + [InlineData(CustomerPaymentProvider.BillCom)] + [InlineData(CustomerPaymentProvider.StripeCharge)] + [InlineData(CustomerPaymentProvider.StripeInvoice)] + [InlineData(CustomerPaymentProvider.Netsuite)] + public void SerializationRoundtrip_Works(CustomerPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AccountingSyncConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }; + + List expectedAccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ]; + bool expectedExcluded = true; + + Assert.Equal(expectedAccountingProviders.Count, model.AccountingProviders.Count); + for (int i = 0; i < expectedAccountingProviders.Count; i++) + { + Assert.Equal(expectedAccountingProviders[i], model.AccountingProviders[i]); + } + Assert.Equal(expectedExcluded, model.Excluded); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ]; + bool expectedExcluded = true; + + Assert.Equal(expectedAccountingProviders.Count, deserialized.AccountingProviders.Count); + for (int i = 0; i < expectedAccountingProviders.Count; i++) + { + Assert.Equal(expectedAccountingProviders[i], deserialized.AccountingProviders[i]); + } + Assert.Equal(expectedExcluded, deserialized.Excluded); + } + + [Fact] + public void Validation_Works() + { + var model = new AccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }; + + model.Validate(); + } +} + +public class AccountingProviderTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AccountingProvider + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }; + + string expectedExternalProviderID = "external_provider_id"; + ApiEnum expectedProviderType = + AccountingProviderProviderType.Quickbooks; + + Assert.Equal(expectedExternalProviderID, model.ExternalProviderID); + Assert.Equal(expectedProviderType, model.ProviderType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AccountingProvider + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AccountingProvider + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedExternalProviderID = "external_provider_id"; + ApiEnum expectedProviderType = + AccountingProviderProviderType.Quickbooks; + + Assert.Equal(expectedExternalProviderID, deserialized.ExternalProviderID); + Assert.Equal(expectedProviderType, deserialized.ProviderType); + } + + [Fact] + public void Validation_Works() + { + var model = new AccountingProvider + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }; + + model.Validate(); + } +} + +public class AccountingProviderProviderTypeTest : TestBase +{ + [Theory] + [InlineData(AccountingProviderProviderType.Quickbooks)] + [InlineData(AccountingProviderProviderType.Netsuite)] + public void Validation_Works(AccountingProviderProviderType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AccountingProviderProviderType.Quickbooks)] + [InlineData(AccountingProviderProviderType.Netsuite)] + public void SerializationRoundtrip_Works(AccountingProviderProviderType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerPaymentConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + List expectedPaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ]; + + Assert.NotNull(model.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, model.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], model.PaymentProviders[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedPaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ]; + + Assert.NotNull(deserialized.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, deserialized.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], deserialized.PaymentProviders[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerPaymentConfiguration { }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerPaymentConfiguration { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerPaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerPaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + model.Validate(); + } +} + +public class CustomerPaymentConfigurationPaymentProviderTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + ApiEnum< + string, + CustomerPaymentConfigurationPaymentProviderProviderType + > expectedProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, model.ProviderType); + Assert.NotNull(model.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + model.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + model.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + CustomerPaymentConfigurationPaymentProviderProviderType + > expectedProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, deserialized.ProviderType); + Assert.NotNull(deserialized.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + deserialized.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + deserialized.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerPaymentConfigurationPaymentProvider + { + ProviderType = CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + model.Validate(); + } +} + +public class CustomerPaymentConfigurationPaymentProviderProviderTypeTest : TestBase +{ + [Theory] + [InlineData(CustomerPaymentConfigurationPaymentProviderProviderType.Stripe)] + public void Validation_Works(CustomerPaymentConfigurationPaymentProviderProviderType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerPaymentConfigurationPaymentProviderProviderType.Stripe)] + public void SerializationRoundtrip_Works( + CustomerPaymentConfigurationPaymentProviderProviderType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReportingConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ReportingConfiguration { Exempt = true }; + + bool expectedExempt = true; + + Assert.Equal(expectedExempt, model.Exempt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ReportingConfiguration { Exempt = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ReportingConfiguration { Exempt = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedExempt = true; + + Assert.Equal(expectedExempt, deserialized.Exempt); + } + + [Fact] + public void Validation_Works() + { + var model = new ReportingConfiguration { Exempt = true }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerUpdateByExternalIDParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerUpdateByExternalIDParamsTest.cs new file mode 100644 index 00000000..e74c089f --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerUpdateByExternalIDParamsTest.cs @@ -0,0 +1,1346 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerUpdateByExternalIDParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerUpdateByExternalIDParams + { + ID = "external_customer_id", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }, + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Currency = "currency", + Email = "dev@stainless.com", + EmailDelivery = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + PaymentProvider = CustomerUpdateByExternalIDParamsPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + ReportingConfiguration = new(true), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxConfiguration = new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + }; + + string expectedID = "external_customer_id"; + NewAccountingSyncConfiguration expectedAccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + List expectedAdditionalEmails = ["string"]; + bool expectedAutoCollection = true; + bool expectedAutoIssuance = true; + AddressInput expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + string expectedCurrency = "currency"; + string expectedEmail = "dev@stainless.com"; + bool expectedEmailDelivery = true; + string expectedExternalCustomerID = "external_customer_id"; + CustomerHierarchyConfig expectedHierarchy = new() + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + CustomerUpdateByExternalIDParamsPaymentConfiguration expectedPaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + ApiEnum expectedPaymentProvider = + CustomerUpdateByExternalIDParamsPaymentProvider.Quickbooks; + string expectedPaymentProviderID = "payment_provider_id"; + NewReportingConfiguration expectedReportingConfiguration = new(true); + AddressInput expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + CustomerUpdateByExternalIDParamsTaxConfiguration expectedTaxConfiguration = + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + CustomerTaxID expectedTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + + Assert.Equal(expectedID, parameters.ID); + Assert.Equal(expectedAccountingSyncConfiguration, parameters.AccountingSyncConfiguration); + Assert.NotNull(parameters.AdditionalEmails); + Assert.Equal(expectedAdditionalEmails.Count, parameters.AdditionalEmails.Count); + for (int i = 0; i < expectedAdditionalEmails.Count; i++) + { + Assert.Equal(expectedAdditionalEmails[i], parameters.AdditionalEmails[i]); + } + Assert.Equal(expectedAutoCollection, parameters.AutoCollection); + Assert.Equal(expectedAutoIssuance, parameters.AutoIssuance); + Assert.Equal(expectedBillingAddress, parameters.BillingAddress); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedEmail, parameters.Email); + Assert.Equal(expectedEmailDelivery, parameters.EmailDelivery); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedHierarchy, parameters.Hierarchy); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedName, parameters.Name); + Assert.Equal(expectedPaymentConfiguration, parameters.PaymentConfiguration); + Assert.Equal(expectedPaymentProvider, parameters.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, parameters.PaymentProviderID); + Assert.Equal(expectedReportingConfiguration, parameters.ReportingConfiguration); + Assert.Equal(expectedShippingAddress, parameters.ShippingAddress); + Assert.Equal(expectedTaxConfiguration, parameters.TaxConfiguration); + Assert.Equal(expectedTaxID, parameters.TaxID); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CustomerUpdateByExternalIDParams { ID = "external_customer_id" }; + + Assert.Null(parameters.AccountingSyncConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("accounting_sync_configuration")); + Assert.Null(parameters.AdditionalEmails); + Assert.False(parameters.RawBodyData.ContainsKey("additional_emails")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AutoIssuance); + Assert.False(parameters.RawBodyData.ContainsKey("auto_issuance")); + Assert.Null(parameters.BillingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("billing_address")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.Email); + Assert.False(parameters.RawBodyData.ContainsKey("email")); + Assert.Null(parameters.EmailDelivery); + Assert.False(parameters.RawBodyData.ContainsKey("email_delivery")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Hierarchy); + Assert.False(parameters.RawBodyData.ContainsKey("hierarchy")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + Assert.Null(parameters.PaymentConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("payment_configuration")); + Assert.Null(parameters.PaymentProvider); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider")); + Assert.Null(parameters.PaymentProviderID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider_id")); + Assert.Null(parameters.ReportingConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("reporting_configuration")); + Assert.Null(parameters.ShippingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("shipping_address")); + Assert.Null(parameters.TaxConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("tax_configuration")); + Assert.Null(parameters.TaxID); + Assert.False(parameters.RawBodyData.ContainsKey("tax_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CustomerUpdateByExternalIDParams + { + ID = "external_customer_id", + + AccountingSyncConfiguration = null, + AdditionalEmails = null, + AutoCollection = null, + AutoIssuance = null, + BillingAddress = null, + Currency = null, + Email = null, + EmailDelivery = null, + ExternalCustomerID = null, + Hierarchy = null, + Metadata = null, + Name = null, + PaymentConfiguration = null, + PaymentProvider = null, + PaymentProviderID = null, + ReportingConfiguration = null, + ShippingAddress = null, + TaxConfiguration = null, + TaxID = null, + }; + + Assert.Null(parameters.AccountingSyncConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("accounting_sync_configuration")); + Assert.Null(parameters.AdditionalEmails); + Assert.False(parameters.RawBodyData.ContainsKey("additional_emails")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AutoIssuance); + Assert.False(parameters.RawBodyData.ContainsKey("auto_issuance")); + Assert.Null(parameters.BillingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("billing_address")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.Email); + Assert.False(parameters.RawBodyData.ContainsKey("email")); + Assert.Null(parameters.EmailDelivery); + Assert.False(parameters.RawBodyData.ContainsKey("email_delivery")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Hierarchy); + Assert.False(parameters.RawBodyData.ContainsKey("hierarchy")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + Assert.Null(parameters.PaymentConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("payment_configuration")); + Assert.Null(parameters.PaymentProvider); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider")); + Assert.Null(parameters.PaymentProviderID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider_id")); + Assert.Null(parameters.ReportingConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("reporting_configuration")); + Assert.Null(parameters.ShippingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("shipping_address")); + Assert.Null(parameters.TaxConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("tax_configuration")); + Assert.Null(parameters.TaxID); + Assert.False(parameters.RawBodyData.ContainsKey("tax_id")); + } +} + +public class CustomerUpdateByExternalIDParamsPaymentConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + List expectedPaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ]; + + Assert.NotNull(model.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, model.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], model.PaymentProviders[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedPaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ]; + + Assert.NotNull(deserialized.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, deserialized.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], deserialized.PaymentProviders[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration { }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > expectedProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, model.ProviderType); + Assert.NotNull(model.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + model.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + model.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > expectedProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, deserialized.ProviderType); + Assert.NotNull(deserialized.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + deserialized.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + deserialized.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderTypeTest + : TestBase +{ + [Theory] + [InlineData( + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe + )] + public void Validation_Works( + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe + )] + public void SerializationRoundtrip_Works( + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerUpdateByExternalIDParamsPaymentProviderTest : TestBase +{ + [Theory] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.Quickbooks)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.BillCom)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.StripeCharge)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.StripeInvoice)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.Netsuite)] + public void Validation_Works(CustomerUpdateByExternalIDParamsPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.Quickbooks)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.BillCom)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.StripeCharge)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.StripeInvoice)] + [InlineData(CustomerUpdateByExternalIDParamsPaymentProvider.Netsuite)] + public void SerializationRoundtrip_Works( + CustomerUpdateByExternalIDParamsPaymentProvider rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerUpdateByExternalIDParamsTaxConfigurationTest : TestBase +{ + [Fact] + public void NewAvalaraValidationWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + } + ); + value.Validate(); + } + + [Fact] + public void NewTaxJarValidationWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new NewTaxJarConfiguration() + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NewSphereValidationWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new NewSphereConfiguration() + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NumeralValidationWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void AnrokValidationWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void StripeValidationWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new CustomerUpdateByExternalIDParamsTaxConfigurationStripe() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NewAvalaraSerializationRoundtripWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewTaxJarSerializationRoundtripWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new NewTaxJarConfiguration() + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSphereSerializationRoundtripWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new NewSphereConfiguration() + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NumeralSerializationRoundtripWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AnrokSerializationRoundtripWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void StripeSerializationRoundtripWorks() + { + CustomerUpdateByExternalIDParamsTaxConfiguration value = new( + new CustomerUpdateByExternalIDParamsTaxConfigurationStripe() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerUpdateByExternalIDParamsTaxConfigurationNumeralTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"numeral\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"numeral\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationNumeral + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateByExternalIDParamsTaxConfigurationAnrokTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"anrok\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"anrok\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationAnrok + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateByExternalIDParamsTaxConfigurationStripeTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"stripe\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"stripe\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateByExternalIDParamsTaxConfigurationStripe + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/CustomerUpdateParamsTest.cs b/src/Orb.Tests/Models/Customers/CustomerUpdateParamsTest.cs new file mode 100644 index 00000000..9c5cc312 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/CustomerUpdateParamsTest.cs @@ -0,0 +1,1319 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class CustomerUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new CustomerUpdateParams + { + CustomerID = "customer_id", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }, + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Currency = "currency", + Email = "dev@stainless.com", + EmailDelivery = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + PaymentProvider = CustomerUpdateParamsPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + ReportingConfiguration = new(true), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxConfiguration = new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + }; + + string expectedCustomerID = "customer_id"; + NewAccountingSyncConfiguration expectedAccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + List expectedAdditionalEmails = ["string"]; + bool expectedAutoCollection = true; + bool expectedAutoIssuance = true; + AddressInput expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + string expectedCurrency = "currency"; + string expectedEmail = "dev@stainless.com"; + bool expectedEmailDelivery = true; + string expectedExternalCustomerID = "external_customer_id"; + CustomerHierarchyConfig expectedHierarchy = new() + { + ChildCustomerIDs = ["string"], + ParentCustomerID = "parent_customer_id", + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + CustomerUpdateParamsPaymentConfiguration expectedPaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + ApiEnum expectedPaymentProvider = + CustomerUpdateParamsPaymentProvider.Quickbooks; + string expectedPaymentProviderID = "payment_provider_id"; + NewReportingConfiguration expectedReportingConfiguration = new(true); + AddressInput expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + CustomerUpdateParamsTaxConfiguration expectedTaxConfiguration = + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + CustomerTaxID expectedTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedAccountingSyncConfiguration, parameters.AccountingSyncConfiguration); + Assert.NotNull(parameters.AdditionalEmails); + Assert.Equal(expectedAdditionalEmails.Count, parameters.AdditionalEmails.Count); + for (int i = 0; i < expectedAdditionalEmails.Count; i++) + { + Assert.Equal(expectedAdditionalEmails[i], parameters.AdditionalEmails[i]); + } + Assert.Equal(expectedAutoCollection, parameters.AutoCollection); + Assert.Equal(expectedAutoIssuance, parameters.AutoIssuance); + Assert.Equal(expectedBillingAddress, parameters.BillingAddress); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedEmail, parameters.Email); + Assert.Equal(expectedEmailDelivery, parameters.EmailDelivery); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedHierarchy, parameters.Hierarchy); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedName, parameters.Name); + Assert.Equal(expectedPaymentConfiguration, parameters.PaymentConfiguration); + Assert.Equal(expectedPaymentProvider, parameters.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, parameters.PaymentProviderID); + Assert.Equal(expectedReportingConfiguration, parameters.ReportingConfiguration); + Assert.Equal(expectedShippingAddress, parameters.ShippingAddress); + Assert.Equal(expectedTaxConfiguration, parameters.TaxConfiguration); + Assert.Equal(expectedTaxID, parameters.TaxID); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new CustomerUpdateParams { CustomerID = "customer_id" }; + + Assert.Null(parameters.AccountingSyncConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("accounting_sync_configuration")); + Assert.Null(parameters.AdditionalEmails); + Assert.False(parameters.RawBodyData.ContainsKey("additional_emails")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AutoIssuance); + Assert.False(parameters.RawBodyData.ContainsKey("auto_issuance")); + Assert.Null(parameters.BillingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("billing_address")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.Email); + Assert.False(parameters.RawBodyData.ContainsKey("email")); + Assert.Null(parameters.EmailDelivery); + Assert.False(parameters.RawBodyData.ContainsKey("email_delivery")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Hierarchy); + Assert.False(parameters.RawBodyData.ContainsKey("hierarchy")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + Assert.Null(parameters.PaymentConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("payment_configuration")); + Assert.Null(parameters.PaymentProvider); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider")); + Assert.Null(parameters.PaymentProviderID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider_id")); + Assert.Null(parameters.ReportingConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("reporting_configuration")); + Assert.Null(parameters.ShippingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("shipping_address")); + Assert.Null(parameters.TaxConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("tax_configuration")); + Assert.Null(parameters.TaxID); + Assert.False(parameters.RawBodyData.ContainsKey("tax_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new CustomerUpdateParams + { + CustomerID = "customer_id", + + AccountingSyncConfiguration = null, + AdditionalEmails = null, + AutoCollection = null, + AutoIssuance = null, + BillingAddress = null, + Currency = null, + Email = null, + EmailDelivery = null, + ExternalCustomerID = null, + Hierarchy = null, + Metadata = null, + Name = null, + PaymentConfiguration = null, + PaymentProvider = null, + PaymentProviderID = null, + ReportingConfiguration = null, + ShippingAddress = null, + TaxConfiguration = null, + TaxID = null, + }; + + Assert.Null(parameters.AccountingSyncConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("accounting_sync_configuration")); + Assert.Null(parameters.AdditionalEmails); + Assert.False(parameters.RawBodyData.ContainsKey("additional_emails")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AutoIssuance); + Assert.False(parameters.RawBodyData.ContainsKey("auto_issuance")); + Assert.Null(parameters.BillingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("billing_address")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.Email); + Assert.False(parameters.RawBodyData.ContainsKey("email")); + Assert.Null(parameters.EmailDelivery); + Assert.False(parameters.RawBodyData.ContainsKey("email_delivery")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Hierarchy); + Assert.False(parameters.RawBodyData.ContainsKey("hierarchy")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + Assert.Null(parameters.PaymentConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("payment_configuration")); + Assert.Null(parameters.PaymentProvider); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider")); + Assert.Null(parameters.PaymentProviderID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_provider_id")); + Assert.Null(parameters.ReportingConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("reporting_configuration")); + Assert.Null(parameters.ShippingAddress); + Assert.False(parameters.RawBodyData.ContainsKey("shipping_address")); + Assert.Null(parameters.TaxConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("tax_configuration")); + Assert.Null(parameters.TaxID); + Assert.False(parameters.RawBodyData.ContainsKey("tax_id")); + } +} + +public class CustomerUpdateParamsPaymentConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + List expectedPaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ]; + + Assert.NotNull(model.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, model.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], model.PaymentProviders[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedPaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ]; + + Assert.NotNull(deserialized.PaymentProviders); + Assert.Equal(expectedPaymentProviders.Count, deserialized.PaymentProviders.Count); + for (int i = 0; i < expectedPaymentProviders.Count; i++) + { + Assert.Equal(expectedPaymentProviders[i], deserialized.PaymentProviders[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration { }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + Assert.Null(model.PaymentProviders); + Assert.False(model.RawData.ContainsKey("payment_providers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateParamsPaymentConfiguration + { + // Null should be interpreted as omitted for these properties + PaymentProviders = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateParamsPaymentConfigurationPaymentProviderTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + ApiEnum< + string, + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType + > expectedProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, model.ProviderType); + Assert.NotNull(model.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + model.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + model.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType + > expectedProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe; + List expectedExcludedPaymentMethodTypes = ["string"]; + + Assert.Equal(expectedProviderType, deserialized.ProviderType); + Assert.NotNull(deserialized.ExcludedPaymentMethodTypes); + Assert.Equal( + expectedExcludedPaymentMethodTypes.Count, + deserialized.ExcludedPaymentMethodTypes.Count + ); + for (int i = 0; i < expectedExcludedPaymentMethodTypes.Count; i++) + { + Assert.Equal( + expectedExcludedPaymentMethodTypes[i], + deserialized.ExcludedPaymentMethodTypes[i] + ); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + Assert.Null(model.ExcludedPaymentMethodTypes); + Assert.False(model.RawData.ContainsKey("excluded_payment_method_types")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateParamsPaymentConfigurationPaymentProvider + { + ProviderType = + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + + // Null should be interpreted as omitted for these properties + ExcludedPaymentMethodTypes = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderTypeTest : TestBase +{ + [Theory] + [InlineData(CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe)] + public void Validation_Works( + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe)] + public void SerializationRoundtrip_Works( + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerUpdateParamsPaymentProviderTest : TestBase +{ + [Theory] + [InlineData(CustomerUpdateParamsPaymentProvider.Quickbooks)] + [InlineData(CustomerUpdateParamsPaymentProvider.BillCom)] + [InlineData(CustomerUpdateParamsPaymentProvider.StripeCharge)] + [InlineData(CustomerUpdateParamsPaymentProvider.StripeInvoice)] + [InlineData(CustomerUpdateParamsPaymentProvider.Netsuite)] + public void Validation_Works(CustomerUpdateParamsPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CustomerUpdateParamsPaymentProvider.Quickbooks)] + [InlineData(CustomerUpdateParamsPaymentProvider.BillCom)] + [InlineData(CustomerUpdateParamsPaymentProvider.StripeCharge)] + [InlineData(CustomerUpdateParamsPaymentProvider.StripeInvoice)] + [InlineData(CustomerUpdateParamsPaymentProvider.Netsuite)] + public void SerializationRoundtrip_Works(CustomerUpdateParamsPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerUpdateParamsTaxConfigurationTest : TestBase +{ + [Fact] + public void NewAvalaraValidationWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + } + ); + value.Validate(); + } + + [Fact] + public void NewTaxJarValidationWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new NewTaxJarConfiguration() + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NewSphereValidationWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new NewSphereConfiguration() + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NumeralValidationWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new CustomerUpdateParamsTaxConfigurationNumeral() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void AnrokValidationWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new CustomerUpdateParamsTaxConfigurationAnrok() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void StripeValidationWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new CustomerUpdateParamsTaxConfigurationStripe() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + value.Validate(); + } + + [Fact] + public void NewAvalaraSerializationRoundtripWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new NewAvalaraTaxConfiguration() + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewTaxJarSerializationRoundtripWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new NewTaxJarConfiguration() + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSphereSerializationRoundtripWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new NewSphereConfiguration() + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NumeralSerializationRoundtripWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new CustomerUpdateParamsTaxConfigurationNumeral() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AnrokSerializationRoundtripWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new CustomerUpdateParamsTaxConfigurationAnrok() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void StripeSerializationRoundtripWorks() + { + CustomerUpdateParamsTaxConfiguration value = new( + new CustomerUpdateParamsTaxConfigurationStripe() + { + TaxExempt = true, + AutomaticTaxEnabled = true, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class CustomerUpdateParamsTaxConfigurationNumeralTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"numeral\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"numeral\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationNumeral + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateParamsTaxConfigurationAnrokTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"anrok\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"anrok\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationAnrok + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class CustomerUpdateParamsTaxConfigurationStripeTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"stripe\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, model.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + JsonElement expectedTaxProvider = JsonSerializer.Deserialize("\"stripe\""); + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.True(JsonElement.DeepEquals(expectedTaxProvider, deserialized.TaxProvider)); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe + { + TaxExempt = true, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe { TaxExempt = true }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe { TaxExempt = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CustomerUpdateParamsTaxConfigurationStripe + { + TaxExempt = true, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/NewAccountingSyncConfigurationTest.cs b/src/Orb.Tests/Models/Customers/NewAccountingSyncConfigurationTest.cs new file mode 100644 index 00000000..2a40f9d8 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/NewAccountingSyncConfigurationTest.cs @@ -0,0 +1,161 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class NewAccountingSyncConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewAccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + + List expectedAccountingProviders = + [ + new() { ExternalProviderID = "external_provider_id", ProviderType = "provider_type" }, + ]; + bool expectedExcluded = true; + + Assert.NotNull(model.AccountingProviders); + Assert.Equal(expectedAccountingProviders.Count, model.AccountingProviders.Count); + for (int i = 0; i < expectedAccountingProviders.Count; i++) + { + Assert.Equal(expectedAccountingProviders[i], model.AccountingProviders[i]); + } + Assert.Equal(expectedExcluded, model.Excluded); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewAccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewAccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAccountingProviders = + [ + new() { ExternalProviderID = "external_provider_id", ProviderType = "provider_type" }, + ]; + bool expectedExcluded = true; + + Assert.NotNull(deserialized.AccountingProviders); + Assert.Equal(expectedAccountingProviders.Count, deserialized.AccountingProviders.Count); + for (int i = 0; i < expectedAccountingProviders.Count; i++) + { + Assert.Equal(expectedAccountingProviders[i], deserialized.AccountingProviders[i]); + } + Assert.Equal(expectedExcluded, deserialized.Excluded); + } + + [Fact] + public void Validation_Works() + { + var model = new NewAccountingSyncConfiguration + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = "provider_type", + }, + ], + Excluded = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewAccountingSyncConfiguration { }; + + Assert.Null(model.AccountingProviders); + Assert.False(model.RawData.ContainsKey("accounting_providers")); + Assert.Null(model.Excluded); + Assert.False(model.RawData.ContainsKey("excluded")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewAccountingSyncConfiguration { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewAccountingSyncConfiguration + { + AccountingProviders = null, + Excluded = null, + }; + + Assert.Null(model.AccountingProviders); + Assert.True(model.RawData.ContainsKey("accounting_providers")); + Assert.Null(model.Excluded); + Assert.True(model.RawData.ContainsKey("excluded")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewAccountingSyncConfiguration + { + AccountingProviders = null, + Excluded = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/NewAvalaraTaxConfigurationTest.cs b/src/Orb.Tests/Models/Customers/NewAvalaraTaxConfigurationTest.cs new file mode 100644 index 00000000..0957cd12 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/NewAvalaraTaxConfigurationTest.cs @@ -0,0 +1,204 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class NewAvalaraTaxConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + + bool expectedTaxExempt = true; + ApiEnum expectedTaxProvider = TaxProvider.Avalara; + bool expectedAutomaticTaxEnabled = true; + string expectedTaxExemptionCode = "tax_exemption_code"; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.Equal(expectedTaxProvider, model.TaxProvider); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + Assert.Equal(expectedTaxExemptionCode, model.TaxExemptionCode); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + ApiEnum expectedTaxProvider = TaxProvider.Avalara; + bool expectedAutomaticTaxEnabled = true; + string expectedTaxExemptionCode = "tax_exemption_code"; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.Equal(expectedTaxProvider, deserialized.TaxProvider); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + Assert.Equal(expectedTaxExemptionCode, deserialized.TaxExemptionCode); + } + + [Fact] + public void Validation_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + AutomaticTaxEnabled = true, + TaxExemptionCode = "tax_exemption_code", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + Assert.Null(model.TaxExemptionCode); + Assert.False(model.RawData.ContainsKey("tax_exemption_code")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + + AutomaticTaxEnabled = null, + TaxExemptionCode = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + Assert.Null(model.TaxExemptionCode); + Assert.True(model.RawData.ContainsKey("tax_exemption_code")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewAvalaraTaxConfiguration + { + TaxExempt = true, + TaxProvider = TaxProvider.Avalara, + + AutomaticTaxEnabled = null, + TaxExemptionCode = null, + }; + + model.Validate(); + } +} + +public class TaxProviderTest : TestBase +{ + [Theory] + [InlineData(TaxProvider.Avalara)] + public void Validation_Works(TaxProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TaxProvider.Avalara)] + public void SerializationRoundtrip_Works(TaxProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/NewReportingConfigurationTest.cs b/src/Orb.Tests/Models/Customers/NewReportingConfigurationTest.cs new file mode 100644 index 00000000..51f48a5b --- /dev/null +++ b/src/Orb.Tests/Models/Customers/NewReportingConfigurationTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class NewReportingConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewReportingConfiguration { Exempt = true }; + + bool expectedExempt = true; + + Assert.Equal(expectedExempt, model.Exempt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewReportingConfiguration { Exempt = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewReportingConfiguration { Exempt = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedExempt = true; + + Assert.Equal(expectedExempt, deserialized.Exempt); + } + + [Fact] + public void Validation_Works() + { + var model = new NewReportingConfiguration { Exempt = true }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Customers/NewSphereConfigurationTest.cs b/src/Orb.Tests/Models/Customers/NewSphereConfigurationTest.cs new file mode 100644 index 00000000..6a38b907 --- /dev/null +++ b/src/Orb.Tests/Models/Customers/NewSphereConfigurationTest.cs @@ -0,0 +1,190 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class NewSphereConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + ApiEnum expectedTaxProvider = + NewSphereConfigurationTaxProvider.Sphere; + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.Equal(expectedTaxProvider, model.TaxProvider); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + ApiEnum expectedTaxProvider = + NewSphereConfigurationTaxProvider.Sphere; + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.Equal(expectedTaxProvider, deserialized.TaxProvider); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewSphereConfiguration + { + TaxExempt = true, + TaxProvider = NewSphereConfigurationTaxProvider.Sphere, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class NewSphereConfigurationTaxProviderTest : TestBase +{ + [Theory] + [InlineData(NewSphereConfigurationTaxProvider.Sphere)] + public void Validation_Works(NewSphereConfigurationTaxProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSphereConfigurationTaxProvider.Sphere)] + public void SerializationRoundtrip_Works(NewSphereConfigurationTaxProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Customers/NewTaxJarConfigurationTest.cs b/src/Orb.Tests/Models/Customers/NewTaxJarConfigurationTest.cs new file mode 100644 index 00000000..9d664b3f --- /dev/null +++ b/src/Orb.Tests/Models/Customers/NewTaxJarConfigurationTest.cs @@ -0,0 +1,190 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; + +namespace Orb.Tests.Models.Customers; + +public class NewTaxJarConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + }; + + bool expectedTaxExempt = true; + ApiEnum expectedTaxProvider = + NewTaxJarConfigurationTaxProvider.Taxjar; + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, model.TaxExempt); + Assert.Equal(expectedTaxProvider, model.TaxProvider); + Assert.Equal(expectedAutomaticTaxEnabled, model.AutomaticTaxEnabled); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedTaxExempt = true; + ApiEnum expectedTaxProvider = + NewTaxJarConfigurationTaxProvider.Taxjar; + bool expectedAutomaticTaxEnabled = true; + + Assert.Equal(expectedTaxExempt, deserialized.TaxExempt); + Assert.Equal(expectedTaxProvider, deserialized.TaxProvider); + Assert.Equal(expectedAutomaticTaxEnabled, deserialized.AutomaticTaxEnabled); + } + + [Fact] + public void Validation_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + AutomaticTaxEnabled = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.False(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + + AutomaticTaxEnabled = null, + }; + + Assert.Null(model.AutomaticTaxEnabled); + Assert.True(model.RawData.ContainsKey("automatic_tax_enabled")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewTaxJarConfiguration + { + TaxExempt = true, + TaxProvider = NewTaxJarConfigurationTaxProvider.Taxjar, + + AutomaticTaxEnabled = null, + }; + + model.Validate(); + } +} + +public class NewTaxJarConfigurationTaxProviderTest : TestBase +{ + [Theory] + [InlineData(NewTaxJarConfigurationTaxProvider.Taxjar)] + public void Validation_Works(NewTaxJarConfigurationTaxProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewTaxJarConfigurationTaxProvider.Taxjar)] + public void SerializationRoundtrip_Works(NewTaxJarConfigurationTaxProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceConfigurationTest.cs b/src/Orb.Tests/Models/DimensionalPriceConfigurationTest.cs new file mode 100644 index 00000000..44c1684c --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceConfigurationTest.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class DimensionalPriceConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + List expectedDimensionValues = ["string"]; + string expectedDimensionalPriceGroupID = "dimensional_price_group_id"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedDimensionalPriceGroupID, model.DimensionalPriceGroupID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDimensionValues = ["string"]; + string expectedDimensionalPriceGroupID = "dimensional_price_group_id"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedDimensionalPriceGroupID, deserialized.DimensionalPriceGroupID); + } + + [Fact] + public void Validation_Works() + { + var model = new DimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParamsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParamsTest.cs new file mode 100644 index 00000000..f7212041 --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParamsTest.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using Orb.Models.DimensionalPriceGroups; + +namespace Orb.Tests.Models.DimensionalPriceGroups; + +public class DimensionalPriceGroupCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new DimensionalPriceGroupCreateParams + { + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + Name = "name", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedBillableMetricID = "billable_metric_id"; + List expectedDimensions = ["region", "instance_type"]; + string expectedName = "name"; + string expectedExternalDimensionalPriceGroupID = "external_dimensional_price_group_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBillableMetricID, parameters.BillableMetricID); + Assert.Equal(expectedDimensions.Count, parameters.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], parameters.Dimensions[i]); + } + Assert.Equal(expectedName, parameters.Name); + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + parameters.ExternalDimensionalPriceGroupID + ); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new DimensionalPriceGroupCreateParams + { + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + Name = "name", + }; + + Assert.Null(parameters.ExternalDimensionalPriceGroupID); + Assert.False(parameters.RawBodyData.ContainsKey("external_dimensional_price_group_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new DimensionalPriceGroupCreateParams + { + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + Name = "name", + + ExternalDimensionalPriceGroupID = null, + Metadata = null, + }; + + Assert.Null(parameters.ExternalDimensionalPriceGroupID); + Assert.False(parameters.RawBodyData.ContainsKey("external_dimensional_price_group_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupDimensionalPriceGroupsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupDimensionalPriceGroupsTest.cs new file mode 100644 index 00000000..e5ab40f6 --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupDimensionalPriceGroupsTest.cs @@ -0,0 +1,158 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.DimensionalPriceGroups; + +namespace Orb.Tests.Models.DimensionalPriceGroups; + +public class DimensionalPriceGroupDimensionalPriceGroupsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DimensionalPriceGroupDimensionalPriceGroups + { + Data = + [ + new() + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DimensionalPriceGroupDimensionalPriceGroups + { + Data = + [ + new() + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DimensionalPriceGroupDimensionalPriceGroups + { + Data = + [ + new() + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new DimensionalPriceGroupDimensionalPriceGroups + { + Data = + [ + new() + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupListParamsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupListParamsTest.cs new file mode 100644 index 00000000..3d77bc8c --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupListParamsTest.cs @@ -0,0 +1,65 @@ +using Orb.Models.DimensionalPriceGroups; + +namespace Orb.Tests.Models.DimensionalPriceGroups; + +public class DimensionalPriceGroupListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new DimensionalPriceGroupListParams { Cursor = "cursor", Limit = 1 }; + + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new DimensionalPriceGroupListParams { Cursor = "cursor" }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new DimensionalPriceGroupListParams + { + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new DimensionalPriceGroupListParams { Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new DimensionalPriceGroupListParams + { + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParamsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParamsTest.cs new file mode 100644 index 00000000..a224d9fe --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.DimensionalPriceGroups; + +namespace Orb.Tests.Models.DimensionalPriceGroups; + +public class DimensionalPriceGroupRetrieveParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new DimensionalPriceGroupRetrieveParams + { + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + string expectedDimensionalPriceGroupID = "dimensional_price_group_id"; + + Assert.Equal(expectedDimensionalPriceGroupID, parameters.DimensionalPriceGroupID); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupTest.cs new file mode 100644 index 00000000..a6e160a8 --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupTest.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.DimensionalPriceGroups; + +namespace Orb.Tests.Models.DimensionalPriceGroups; + +public class DimensionalPriceGroupTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DimensionalPriceGroup + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + string expectedID = "id"; + string expectedBillableMetricID = "billable_metric_id"; + List expectedDimensions = ["region", "instance_type"]; + string expectedExternalDimensionalPriceGroupID = "my_dimensional_price_group_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedDimensions.Count, model.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], model.Dimensions[i]); + } + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + model.ExternalDimensionalPriceGroupID + ); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DimensionalPriceGroup + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DimensionalPriceGroup + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedBillableMetricID = "billable_metric_id"; + List expectedDimensions = ["region", "instance_type"]; + string expectedExternalDimensionalPriceGroupID = "my_dimensional_price_group_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedDimensions.Count, deserialized.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], deserialized.Dimensions[i]); + } + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + deserialized.ExternalDimensionalPriceGroupID + ); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new DimensionalPriceGroup + { + ID = "id", + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + ExternalDimensionalPriceGroupID = "my_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupUpdateParamsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupUpdateParamsTest.cs new file mode 100644 index 00000000..b33720bf --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/DimensionalPriceGroupUpdateParamsTest.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using Orb.Models.DimensionalPriceGroups; + +namespace Orb.Tests.Models.DimensionalPriceGroups; + +public class DimensionalPriceGroupUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new DimensionalPriceGroupUpdateParams + { + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedDimensionalPriceGroupID = "dimensional_price_group_id"; + string expectedExternalDimensionalPriceGroupID = "external_dimensional_price_group_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedDimensionalPriceGroupID, parameters.DimensionalPriceGroupID); + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + parameters.ExternalDimensionalPriceGroupID + ); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new DimensionalPriceGroupUpdateParams + { + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Null(parameters.ExternalDimensionalPriceGroupID); + Assert.False(parameters.RawBodyData.ContainsKey("external_dimensional_price_group_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new DimensionalPriceGroupUpdateParams + { + DimensionalPriceGroupID = "dimensional_price_group_id", + + ExternalDimensionalPriceGroupID = null, + Metadata = null, + }; + + Assert.Null(parameters.ExternalDimensionalPriceGroupID); + Assert.False(parameters.RawBodyData.ContainsKey("external_dimensional_price_group_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParamsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParamsTest.cs new file mode 100644 index 00000000..45580a4b --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParamsTest.cs @@ -0,0 +1,22 @@ +using Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +namespace Orb.Tests.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +public class ExternalDimensionalPriceGroupIDRetrieveParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalDimensionalPriceGroupIDRetrieveParams + { + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + + string expectedExternalDimensionalPriceGroupID = "external_dimensional_price_group_id"; + + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + parameters.ExternalDimensionalPriceGroupID + ); + } +} diff --git a/src/Orb.Tests/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDUpdateParamsTest.cs b/src/Orb.Tests/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDUpdateParamsTest.cs new file mode 100644 index 00000000..bef8c778 --- /dev/null +++ b/src/Orb.Tests/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDUpdateParamsTest.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +namespace Orb.Tests.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +public class ExternalDimensionalPriceGroupIDUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalDimensionalPriceGroupIDUpdateParams + { + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + ExternalDimensionalPriceGroupIDValue = "external_dimensional_price_group_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedExternalDimensionalPriceGroupID = "external_dimensional_price_group_id"; + string expectedExternalDimensionalPriceGroupIDValue = "external_dimensional_price_group_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + parameters.ExternalDimensionalPriceGroupID + ); + Assert.Equal( + expectedExternalDimensionalPriceGroupIDValue, + parameters.ExternalDimensionalPriceGroupIDValue + ); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ExternalDimensionalPriceGroupIDUpdateParams + { + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + + Assert.Null(parameters.ExternalDimensionalPriceGroupIDValue); + Assert.False(parameters.RawBodyData.ContainsKey("external_dimensional_price_group_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ExternalDimensionalPriceGroupIDUpdateParams + { + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + + ExternalDimensionalPriceGroupIDValue = null, + Metadata = null, + }; + + Assert.Null(parameters.ExternalDimensionalPriceGroupIDValue); + Assert.False(parameters.RawBodyData.ContainsKey("external_dimensional_price_group_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillCloseParamsTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillCloseParamsTest.cs new file mode 100644 index 00000000..b2cb6ae1 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillCloseParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillCloseParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BackfillCloseParams { BackfillID = "backfill_id" }; + + string expectedBackfillID = "backfill_id"; + + Assert.Equal(expectedBackfillID, parameters.BackfillID); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillCloseResponseTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillCloseResponseTest.cs new file mode 100644 index 00000000..c6216812 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillCloseResponseTest.cs @@ -0,0 +1,297 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillCloseResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillCloseResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCloseTime, model.CloseTime); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedEventsIngested, model.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, model.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, model.RevertedAt); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, model.DeprecationFilter); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillCloseResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCloseTime, deserialized.CloseTime); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedEventsIngested, deserialized.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, deserialized.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, deserialized.RevertedAt); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, deserialized.DeprecationFilter); + } + + [Fact] + public void Validation_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.DeprecationFilter); + Assert.False(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + Assert.Null(model.DeprecationFilter); + Assert.True(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BackfillCloseResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillCloseResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + model.Validate(); + } +} + +public class BackfillCloseResponseStatusTest : TestBase +{ + [Theory] + [InlineData(BackfillCloseResponseStatus.Pending)] + [InlineData(BackfillCloseResponseStatus.Reflected)] + [InlineData(BackfillCloseResponseStatus.PendingRevert)] + [InlineData(BackfillCloseResponseStatus.Reverted)] + public void Validation_Works(BackfillCloseResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BackfillCloseResponseStatus.Pending)] + [InlineData(BackfillCloseResponseStatus.Reflected)] + [InlineData(BackfillCloseResponseStatus.PendingRevert)] + [InlineData(BackfillCloseResponseStatus.Reverted)] + public void SerializationRoundtrip_Works(BackfillCloseResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillCreateParamsTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillCreateParamsTest.cs new file mode 100644 index 00000000..cbad5bd3 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillCreateParamsTest.cs @@ -0,0 +1,121 @@ +using System; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BackfillCreateParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + ExternalCustomerID = "external_customer_id", + ReplaceExistingEvents = true, + }; + + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + string expectedExternalCustomerID = "external_customer_id"; + bool expectedReplaceExistingEvents = true; + + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedCloseTime, parameters.CloseTime); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedDeprecationFilter, parameters.DeprecationFilter); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedReplaceExistingEvents, parameters.ReplaceExistingEvents); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BackfillCreateParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + ExternalCustomerID = "external_customer_id", + }; + + Assert.Null(parameters.ReplaceExistingEvents); + Assert.False(parameters.RawBodyData.ContainsKey("replace_existing_events")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new BackfillCreateParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + ExternalCustomerID = "external_customer_id", + + // Null should be interpreted as omitted for these properties + ReplaceExistingEvents = null, + }; + + Assert.Null(parameters.ReplaceExistingEvents); + Assert.False(parameters.RawBodyData.ContainsKey("replace_existing_events")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BackfillCreateParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ReplaceExistingEvents = true, + }; + + Assert.Null(parameters.CloseTime); + Assert.False(parameters.RawBodyData.ContainsKey("close_time")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.DeprecationFilter); + Assert.False(parameters.RawBodyData.ContainsKey("deprecation_filter")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new BackfillCreateParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ReplaceExistingEvents = true, + + CloseTime = null, + CustomerID = null, + DeprecationFilter = null, + ExternalCustomerID = null, + }; + + Assert.Null(parameters.CloseTime); + Assert.False(parameters.RawBodyData.ContainsKey("close_time")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.DeprecationFilter); + Assert.False(parameters.RawBodyData.ContainsKey("deprecation_filter")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillCreateResponseTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillCreateResponseTest.cs new file mode 100644 index 00000000..d0d30d6f --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillCreateResponseTest.cs @@ -0,0 +1,295 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillCreateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = Status.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCloseTime, model.CloseTime); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedEventsIngested, model.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, model.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, model.RevertedAt); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, model.DeprecationFilter); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = Status.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCloseTime, deserialized.CloseTime); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedEventsIngested, deserialized.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, deserialized.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, deserialized.RevertedAt); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, deserialized.DeprecationFilter); + } + + [Fact] + public void Validation_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.DeprecationFilter); + Assert.False(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + Assert.Null(model.DeprecationFilter); + Assert.True(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BackfillCreateResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + model.Validate(); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Pending)] + [InlineData(Status.Reflected)] + [InlineData(Status.PendingRevert)] + [InlineData(Status.Reverted)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Pending)] + [InlineData(Status.Reflected)] + [InlineData(Status.PendingRevert)] + [InlineData(Status.Reverted)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillFetchParamsTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillFetchParamsTest.cs new file mode 100644 index 00000000..6f893c26 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BackfillFetchParams { BackfillID = "backfill_id" }; + + string expectedBackfillID = "backfill_id"; + + Assert.Equal(expectedBackfillID, parameters.BackfillID); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillFetchResponseTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillFetchResponseTest.cs new file mode 100644 index 00000000..3f16a3a2 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillFetchResponseTest.cs @@ -0,0 +1,297 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillFetchResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillFetchResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCloseTime, model.CloseTime); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedEventsIngested, model.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, model.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, model.RevertedAt); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, model.DeprecationFilter); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillFetchResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCloseTime, deserialized.CloseTime); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedEventsIngested, deserialized.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, deserialized.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, deserialized.RevertedAt); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, deserialized.DeprecationFilter); + } + + [Fact] + public void Validation_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.DeprecationFilter); + Assert.False(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + Assert.Null(model.DeprecationFilter); + Assert.True(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BackfillFetchResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillFetchResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + model.Validate(); + } +} + +public class BackfillFetchResponseStatusTest : TestBase +{ + [Theory] + [InlineData(BackfillFetchResponseStatus.Pending)] + [InlineData(BackfillFetchResponseStatus.Reflected)] + [InlineData(BackfillFetchResponseStatus.PendingRevert)] + [InlineData(BackfillFetchResponseStatus.Reverted)] + public void Validation_Works(BackfillFetchResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BackfillFetchResponseStatus.Pending)] + [InlineData(BackfillFetchResponseStatus.Reflected)] + [InlineData(BackfillFetchResponseStatus.PendingRevert)] + [InlineData(BackfillFetchResponseStatus.Reverted)] + public void SerializationRoundtrip_Works(BackfillFetchResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillListPageResponseTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillListPageResponseTest.cs new file mode 100644 index 00000000..68176075 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillListPageResponseTest.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BackfillListPageResponse + { + Data = + [ + new() + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BackfillListPageResponse + { + Data = + [ + new() + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BackfillListPageResponse + { + Data = + [ + new() + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new BackfillListPageResponse + { + Data = + [ + new() + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillListParamsTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillListParamsTest.cs new file mode 100644 index 00000000..e1bf3d14 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillListParamsTest.cs @@ -0,0 +1,65 @@ +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BackfillListParams { Cursor = "cursor", Limit = 1 }; + + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BackfillListParams { Cursor = "cursor" }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new BackfillListParams + { + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new BackfillListParams { Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new BackfillListParams + { + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillListResponseTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillListResponseTest.cs new file mode 100644 index 00000000..a9acbcc1 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillListResponseTest.cs @@ -0,0 +1,297 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillListResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillListResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCloseTime, model.CloseTime); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedEventsIngested, model.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, model.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, model.RevertedAt); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, model.DeprecationFilter); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillListResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCloseTime, deserialized.CloseTime); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedEventsIngested, deserialized.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, deserialized.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, deserialized.RevertedAt); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, deserialized.DeprecationFilter); + } + + [Fact] + public void Validation_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.DeprecationFilter); + Assert.False(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + Assert.Null(model.DeprecationFilter); + Assert.True(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BackfillListResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillListResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + model.Validate(); + } +} + +public class BackfillListResponseStatusTest : TestBase +{ + [Theory] + [InlineData(BackfillListResponseStatus.Pending)] + [InlineData(BackfillListResponseStatus.Reflected)] + [InlineData(BackfillListResponseStatus.PendingRevert)] + [InlineData(BackfillListResponseStatus.Reverted)] + public void Validation_Works(BackfillListResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BackfillListResponseStatus.Pending)] + [InlineData(BackfillListResponseStatus.Reflected)] + [InlineData(BackfillListResponseStatus.PendingRevert)] + [InlineData(BackfillListResponseStatus.Reverted)] + public void SerializationRoundtrip_Works(BackfillListResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillRevertParamsTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillRevertParamsTest.cs new file mode 100644 index 00000000..fccfe289 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillRevertParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillRevertParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new BackfillRevertParams { BackfillID = "backfill_id" }; + + string expectedBackfillID = "backfill_id"; + + Assert.Equal(expectedBackfillID, parameters.BackfillID); + } +} diff --git a/src/Orb.Tests/Models/Events/Backfills/BackfillRevertResponseTest.cs b/src/Orb.Tests/Models/Events/Backfills/BackfillRevertResponseTest.cs new file mode 100644 index 00000000..fe4d5148 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Backfills/BackfillRevertResponseTest.cs @@ -0,0 +1,295 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events.Backfills; + +namespace Orb.Tests.Models.Events.Backfills; + +public class BackfillRevertResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillRevertResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCloseTime, model.CloseTime); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedEventsIngested, model.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, model.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, model.RevertedAt); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, model.DeprecationFilter); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + long expectedEventsIngested = 0; + bool expectedReplaceExistingEvents = true; + DateTimeOffset expectedRevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + BackfillRevertResponseStatus.Pending; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedDeprecationFilter = + "my_numeric_property > 100 AND my_other_property = 'bar'"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCloseTime, deserialized.CloseTime); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedEventsIngested, deserialized.EventsIngested); + Assert.Equal(expectedReplaceExistingEvents, deserialized.ReplaceExistingEvents); + Assert.Equal(expectedRevertedAt, deserialized.RevertedAt); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + Assert.Equal(expectedDeprecationFilter, deserialized.DeprecationFilter); + } + + [Fact] + public void Validation_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.DeprecationFilter); + Assert.False(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + Assert.Null(model.DeprecationFilter); + Assert.True(model.RawData.ContainsKey("deprecation_filter")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BackfillRevertResponse + { + ID = "id", + CloseTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + EventsIngested = 0, + ReplaceExistingEvents = true, + RevertedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = BackfillRevertResponseStatus.Pending, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + DeprecationFilter = null, + }; + + model.Validate(); + } +} + +public class BackfillRevertResponseStatusTest : TestBase +{ + [Theory] + [InlineData(BackfillRevertResponseStatus.Pending)] + [InlineData(BackfillRevertResponseStatus.Reflected)] + [InlineData(BackfillRevertResponseStatus.PendingRevert)] + [InlineData(BackfillRevertResponseStatus.Reverted)] + public void Validation_Works(BackfillRevertResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BackfillRevertResponseStatus.Pending)] + [InlineData(BackfillRevertResponseStatus.Reflected)] + [InlineData(BackfillRevertResponseStatus.PendingRevert)] + [InlineData(BackfillRevertResponseStatus.Reverted)] + public void SerializationRoundtrip_Works(BackfillRevertResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Events/EventDeprecateParamsTest.cs b/src/Orb.Tests/Models/Events/EventDeprecateParamsTest.cs new file mode 100644 index 00000000..33796adf --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventDeprecateParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventDeprecateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new EventDeprecateParams { EventID = "event_id" }; + + string expectedEventID = "event_id"; + + Assert.Equal(expectedEventID, parameters.EventID); + } +} diff --git a/src/Orb.Tests/Models/Events/EventDeprecateResponseTest.cs b/src/Orb.Tests/Models/Events/EventDeprecateResponseTest.cs new file mode 100644 index 00000000..7a9e22da --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventDeprecateResponseTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventDeprecateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventDeprecateResponse { Deprecated = "deprecated" }; + + string expectedDeprecated = "deprecated"; + + Assert.Equal(expectedDeprecated, model.Deprecated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventDeprecateResponse { Deprecated = "deprecated" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventDeprecateResponse { Deprecated = "deprecated" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedDeprecated = "deprecated"; + + Assert.Equal(expectedDeprecated, deserialized.Deprecated); + } + + [Fact] + public void Validation_Works() + { + var model = new EventDeprecateResponse { Deprecated = "deprecated" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/EventIngestParamsTest.cs b/src/Orb.Tests/Models/Events/EventIngestParamsTest.cs new file mode 100644 index 00000000..425899d4 --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventIngestParamsTest.cs @@ -0,0 +1,381 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventIngestParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new EventIngestParams + { + Events = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + BackfillID = "backfill_id", + Debug = true, + }; + + List expectedEvents = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ]; + string expectedBackfillID = "backfill_id"; + bool expectedDebug = true; + + Assert.Equal(expectedEvents.Count, parameters.Events.Count); + for (int i = 0; i < expectedEvents.Count; i++) + { + Assert.Equal(expectedEvents[i], parameters.Events[i]); + } + Assert.Equal(expectedBackfillID, parameters.BackfillID); + Assert.Equal(expectedDebug, parameters.Debug); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new EventIngestParams + { + Events = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + BackfillID = "backfill_id", + }; + + Assert.Null(parameters.Debug); + Assert.False(parameters.RawQueryData.ContainsKey("debug")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new EventIngestParams + { + Events = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + BackfillID = "backfill_id", + + // Null should be interpreted as omitted for these properties + Debug = null, + }; + + Assert.Null(parameters.Debug); + Assert.False(parameters.RawQueryData.ContainsKey("debug")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new EventIngestParams + { + Events = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + Debug = true, + }; + + Assert.Null(parameters.BackfillID); + Assert.False(parameters.RawQueryData.ContainsKey("backfill_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new EventIngestParams + { + Events = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + Debug = true, + + BackfillID = null, + }; + + Assert.Null(parameters.BackfillID); + Assert.False(parameters.RawQueryData.ContainsKey("backfill_id")); + } +} + +public class EventTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string expectedEventName = "event_name"; + string expectedIdempotencyKey = "idempotency_key"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedEventName, model.EventName); + Assert.Equal(expectedIdempotencyKey, model.IdempotencyKey); + Assert.Equal(expectedProperties.Count, model.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(model.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, model.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, model.Timestamp); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedExternalCustomerID, model.ExternalCustomerID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedEventName = "event_name"; + string expectedIdempotencyKey = "idempotency_key"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedEventName, deserialized.EventName); + Assert.Equal(expectedIdempotencyKey, deserialized.IdempotencyKey); + Assert.Equal(expectedProperties.Count, deserialized.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(deserialized.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, deserialized.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, deserialized.Timestamp); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedExternalCustomerID, deserialized.ExternalCustomerID); + } + + [Fact] + public void Validation_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + Assert.Null(model.CustomerID); + Assert.False(model.RawData.ContainsKey("customer_id")); + Assert.Null(model.ExternalCustomerID); + Assert.False(model.RawData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + + CustomerID = null, + ExternalCustomerID = null, + }; + + Assert.Null(model.CustomerID); + Assert.True(model.RawData.ContainsKey("customer_id")); + Assert.Null(model.ExternalCustomerID); + Assert.True(model.RawData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Event + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + + CustomerID = null, + ExternalCustomerID = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/EventIngestResponseTest.cs b/src/Orb.Tests/Models/Events/EventIngestResponseTest.cs new file mode 100644 index 00000000..627ed88d --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventIngestResponseTest.cs @@ -0,0 +1,299 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventIngestResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + Debug = new() { Duplicate = ["string"], Ingested = ["string"] }, + }; + + List expectedValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ]; + Debug expectedDebug = new() { Duplicate = ["string"], Ingested = ["string"] }; + + Assert.Equal(expectedValidationFailed.Count, model.ValidationFailed.Count); + for (int i = 0; i < expectedValidationFailed.Count; i++) + { + Assert.Equal(expectedValidationFailed[i], model.ValidationFailed[i]); + } + Assert.Equal(expectedDebug, model.Debug); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + Debug = new() { Duplicate = ["string"], Ingested = ["string"] }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + Debug = new() { Duplicate = ["string"], Ingested = ["string"] }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ]; + Debug expectedDebug = new() { Duplicate = ["string"], Ingested = ["string"] }; + + Assert.Equal(expectedValidationFailed.Count, deserialized.ValidationFailed.Count); + for (int i = 0; i < expectedValidationFailed.Count; i++) + { + Assert.Equal(expectedValidationFailed[i], deserialized.ValidationFailed[i]); + } + Assert.Equal(expectedDebug, deserialized.Debug); + } + + [Fact] + public void Validation_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + Debug = new() { Duplicate = ["string"], Ingested = ["string"] }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + }; + + Assert.Null(model.Debug); + Assert.False(model.RawData.ContainsKey("debug")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + + Debug = null, + }; + + Assert.Null(model.Debug); + Assert.True(model.RawData.ContainsKey("debug")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventIngestResponse + { + ValidationFailed = + [ + new() { IdempotencyKey = "idempotency_key", ValidationErrors = ["string"] }, + ], + + Debug = null, + }; + + model.Validate(); + } +} + +public class ValidationFailedTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ValidationFailed + { + IdempotencyKey = "idempotency_key", + ValidationErrors = ["string"], + }; + + string expectedIdempotencyKey = "idempotency_key"; + List expectedValidationErrors = ["string"]; + + Assert.Equal(expectedIdempotencyKey, model.IdempotencyKey); + Assert.Equal(expectedValidationErrors.Count, model.ValidationErrors.Count); + for (int i = 0; i < expectedValidationErrors.Count; i++) + { + Assert.Equal(expectedValidationErrors[i], model.ValidationErrors[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ValidationFailed + { + IdempotencyKey = "idempotency_key", + ValidationErrors = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ValidationFailed + { + IdempotencyKey = "idempotency_key", + ValidationErrors = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedIdempotencyKey = "idempotency_key"; + List expectedValidationErrors = ["string"]; + + Assert.Equal(expectedIdempotencyKey, deserialized.IdempotencyKey); + Assert.Equal(expectedValidationErrors.Count, deserialized.ValidationErrors.Count); + for (int i = 0; i < expectedValidationErrors.Count; i++) + { + Assert.Equal(expectedValidationErrors[i], deserialized.ValidationErrors[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ValidationFailed + { + IdempotencyKey = "idempotency_key", + ValidationErrors = ["string"], + }; + + model.Validate(); + } +} + +public class DebugTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Debug { Duplicate = ["string"], Ingested = ["string"] }; + + List expectedDuplicate = ["string"]; + List expectedIngested = ["string"]; + + Assert.Equal(expectedDuplicate.Count, model.Duplicate.Count); + for (int i = 0; i < expectedDuplicate.Count; i++) + { + Assert.Equal(expectedDuplicate[i], model.Duplicate[i]); + } + Assert.Equal(expectedIngested.Count, model.Ingested.Count); + for (int i = 0; i < expectedIngested.Count; i++) + { + Assert.Equal(expectedIngested[i], model.Ingested[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Debug { Duplicate = ["string"], Ingested = ["string"] }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Debug { Duplicate = ["string"], Ingested = ["string"] }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDuplicate = ["string"]; + List expectedIngested = ["string"]; + + Assert.Equal(expectedDuplicate.Count, deserialized.Duplicate.Count); + for (int i = 0; i < expectedDuplicate.Count; i++) + { + Assert.Equal(expectedDuplicate[i], deserialized.Duplicate[i]); + } + Assert.Equal(expectedIngested.Count, deserialized.Ingested.Count); + for (int i = 0; i < expectedIngested.Count; i++) + { + Assert.Equal(expectedIngested[i], deserialized.Ingested[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Debug { Duplicate = ["string"], Ingested = ["string"] }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/EventSearchParamsTest.cs b/src/Orb.Tests/Models/Events/EventSearchParamsTest.cs new file mode 100644 index 00000000..37dbd9b1 --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventSearchParamsTest.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventSearchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new EventSearchParams + { + EventIDs = ["string"], + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + List expectedEventIDs = ["string"]; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedEventIDs.Count, parameters.EventIDs.Count); + for (int i = 0; i < expectedEventIDs.Count; i++) + { + Assert.Equal(expectedEventIDs[i], parameters.EventIDs[i]); + } + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new EventSearchParams { EventIDs = ["string"] }; + + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawBodyData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawBodyData.ContainsKey("timeframe_start")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new EventSearchParams + { + EventIDs = ["string"], + + TimeframeEnd = null, + TimeframeStart = null, + }; + + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawBodyData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawBodyData.ContainsKey("timeframe_start")); + } +} diff --git a/src/Orb.Tests/Models/Events/EventSearchResponseTest.cs b/src/Orb.Tests/Models/Events/EventSearchResponseTest.cs new file mode 100644 index 00000000..579b3bef --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventSearchResponseTest.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventSearchResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventSearchResponse + { + Data = + [ + new() + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + ], + }; + + List expectedData = + [ + new() + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventSearchResponse + { + Data = + [ + new() + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventSearchResponse + { + Data = + [ + new() + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new EventSearchResponse + { + Data = + [ + new() + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + ], + }; + + model.Validate(); + } +} + +public class DataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Data + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + string expectedID = "id"; + string expectedCustomerID = "customer_id"; + bool expectedDeprecated = true; + string expectedEventName = "event_name"; + string expectedExternalCustomerID = "external_customer_id"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedDeprecated, model.Deprecated); + Assert.Equal(expectedEventName, model.EventName); + Assert.Equal(expectedExternalCustomerID, model.ExternalCustomerID); + Assert.Equal(expectedProperties.Count, model.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(model.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, model.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, model.Timestamp); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Data + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Data + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedCustomerID = "customer_id"; + bool expectedDeprecated = true; + string expectedEventName = "event_name"; + string expectedExternalCustomerID = "external_customer_id"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedDeprecated, deserialized.Deprecated); + Assert.Equal(expectedEventName, deserialized.EventName); + Assert.Equal(expectedExternalCustomerID, deserialized.ExternalCustomerID); + Assert.Equal(expectedProperties.Count, deserialized.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(deserialized.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, deserialized.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, deserialized.Timestamp); + } + + [Fact] + public void Validation_Works() + { + var model = new Data + { + ID = "id", + CustomerID = "customer_id", + Deprecated = true, + EventName = "event_name", + ExternalCustomerID = "external_customer_id", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/EventUpdateParamsTest.cs b/src/Orb.Tests/Models/Events/EventUpdateParamsTest.cs new file mode 100644 index 00000000..7d3774a6 --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventUpdateParamsTest.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new EventUpdateParams + { + EventID = "event_id", + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string expectedEventID = "event_id"; + string expectedEventName = "event_name"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedEventID, parameters.EventID); + Assert.Equal(expectedEventName, parameters.EventName); + Assert.Equal(expectedProperties.Count, parameters.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(parameters.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, parameters.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, parameters.Timestamp); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new EventUpdateParams + { + EventID = "event_id", + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new EventUpdateParams + { + EventID = "event_id", + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + + CustomerID = null, + ExternalCustomerID = null, + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } +} diff --git a/src/Orb.Tests/Models/Events/EventUpdateResponseTest.cs b/src/Orb.Tests/Models/Events/EventUpdateResponseTest.cs new file mode 100644 index 00000000..04ace5c2 --- /dev/null +++ b/src/Orb.Tests/Models/Events/EventUpdateResponseTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models.Events; + +namespace Orb.Tests.Models.Events; + +public class EventUpdateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventUpdateResponse { Amended = "amended" }; + + string expectedAmended = "amended"; + + Assert.Equal(expectedAmended, model.Amended); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventUpdateResponse { Amended = "amended" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventUpdateResponse { Amended = "amended" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmended = "amended"; + + Assert.Equal(expectedAmended, deserialized.Amended); + } + + [Fact] + public void Validation_Works() + { + var model = new EventUpdateResponse { Amended = "amended" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/Volume/EventVolumesTest.cs b/src/Orb.Tests/Models/Events/Volume/EventVolumesTest.cs new file mode 100644 index 00000000..34622181 --- /dev/null +++ b/src/Orb.Tests/Models/Events/Volume/EventVolumesTest.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Events.Volume; + +namespace Orb.Tests.Models.Events.Volume; + +public class EventVolumesTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventVolumes + { + Data = + [ + new() + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + }; + + List expectedData = + [ + new() + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventVolumes + { + Data = + [ + new() + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventVolumes + { + Data = + [ + new() + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new EventVolumes + { + Data = + [ + new() + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + }; + + model.Validate(); + } +} + +public class DataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Data + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + long expectedCount = 0; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCount, model.Count); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Data + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Data + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedCount = 0; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCount, deserialized.Count); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + } + + [Fact] + public void Validation_Works() + { + var model = new Data + { + Count = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Events/Volume/VolumeListParamsTest.cs b/src/Orb.Tests/Models/Events/Volume/VolumeListParamsTest.cs new file mode 100644 index 00000000..69ef149c --- /dev/null +++ b/src/Orb.Tests/Models/Events/Volume/VolumeListParamsTest.cs @@ -0,0 +1,93 @@ +using System; +using Orb.Models.Events.Volume; + +namespace Orb.Tests.Models.Events.Volume; + +public class VolumeListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new VolumeListParams + { + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + Limit = 1, + TimeframeEnd = DateTimeOffset.Parse("2024-10-11T06:00:00Z"), + }; + + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + long expectedLimit = 1; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2024-10-11T06:00:00Z"); + + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new VolumeListParams + { + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new VolumeListParams + { + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + TimeframeEnd = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new VolumeListParams + { + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Limit = 1, + TimeframeEnd = DateTimeOffset.Parse("2024-10-11T06:00:00Z"), + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new VolumeListParams + { + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Limit = 1, + TimeframeEnd = DateTimeOffset.Parse("2024-10-11T06:00:00Z"), + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/FixedFeeQuantityScheduleEntryTest.cs b/src/Orb.Tests/Models/FixedFeeQuantityScheduleEntryTest.cs new file mode 100644 index 00000000..3f18c640 --- /dev/null +++ b/src/Orb.Tests/Models/FixedFeeQuantityScheduleEntryTest.cs @@ -0,0 +1,87 @@ +using System; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class FixedFeeQuantityScheduleEntryTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new FixedFeeQuantityScheduleEntry + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPriceID = "price_id"; + double expectedQuantity = 0; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new FixedFeeQuantityScheduleEntry + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new FixedFeeQuantityScheduleEntry + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPriceID = "price_id"; + double expectedQuantity = 0; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new FixedFeeQuantityScheduleEntry + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/FixedFeeQuantityTransitionTest.cs b/src/Orb.Tests/Models/FixedFeeQuantityTransitionTest.cs new file mode 100644 index 00000000..150358b6 --- /dev/null +++ b/src/Orb.Tests/Models/FixedFeeQuantityTransitionTest.cs @@ -0,0 +1,79 @@ +using System; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class FixedFeeQuantityTransitionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }; + + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPriceID = "price_id"; + long expectedQuantity = 0; + + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedQuantity, model.Quantity); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPriceID = "price_id"; + long expectedQuantity = 0; + + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedQuantity, deserialized.Quantity); + } + + [Fact] + public void Validation_Works() + { + var model = new FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/InvoiceLevelDiscountTest.cs b/src/Orb.Tests/Models/InvoiceLevelDiscountTest.cs new file mode 100644 index 00000000..6e815690 --- /dev/null +++ b/src/Orb.Tests/Models/InvoiceLevelDiscountTest.cs @@ -0,0 +1,162 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class InvoiceLevelDiscountTest : TestBase +{ + [Fact] + public void PercentageValidationWorks() + { + InvoiceLevelDiscount value = new( + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmountValidationWorks() + { + InvoiceLevelDiscount value = new( + new AmountDiscount() + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void TrialValidationWorks() + { + InvoiceLevelDiscount value = new( + new TrialDiscount() + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + InvoiceLevelDiscount value = new( + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + InvoiceLevelDiscount value = new( + new AmountDiscount() + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TrialSerializationRoundtripWorks() + { + InvoiceLevelDiscount value = new( + new TrialDiscount() + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/InvoiceLineItems/InvoiceLineItemCreateParamsTest.cs b/src/Orb.Tests/Models/InvoiceLineItems/InvoiceLineItemCreateParamsTest.cs new file mode 100644 index 00000000..898b31b0 --- /dev/null +++ b/src/Orb.Tests/Models/InvoiceLineItems/InvoiceLineItemCreateParamsTest.cs @@ -0,0 +1,76 @@ +using Orb.Models.InvoiceLineItems; + +namespace Orb.Tests.Models.InvoiceLineItems; + +public class InvoiceLineItemCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceLineItemCreateParams + { + Amount = "12.00", + EndDate = "2023-09-22", + InvoiceID = "4khy3nwzktxv7", + Quantity = 1, + StartDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + Name = "Item Name", + }; + + string expectedAmount = "12.00"; + string expectedEndDate = "2023-09-22"; + string expectedInvoiceID = "4khy3nwzktxv7"; + double expectedQuantity = 1; + string expectedStartDate = "2023-09-22"; + string expectedItemID = "4khy3nwzktxv7"; + string expectedName = "Item Name"; + + Assert.Equal(expectedAmount, parameters.Amount); + Assert.Equal(expectedEndDate, parameters.EndDate); + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + Assert.Equal(expectedQuantity, parameters.Quantity); + Assert.Equal(expectedStartDate, parameters.StartDate); + Assert.Equal(expectedItemID, parameters.ItemID); + Assert.Equal(expectedName, parameters.Name); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceLineItemCreateParams + { + Amount = "12.00", + EndDate = "2023-09-22", + InvoiceID = "4khy3nwzktxv7", + Quantity = 1, + StartDate = "2023-09-22", + }; + + Assert.Null(parameters.ItemID); + Assert.False(parameters.RawBodyData.ContainsKey("item_id")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new InvoiceLineItemCreateParams + { + Amount = "12.00", + EndDate = "2023-09-22", + InvoiceID = "4khy3nwzktxv7", + Quantity = 1, + StartDate = "2023-09-22", + + ItemID = null, + Name = null, + }; + + Assert.Null(parameters.ItemID); + Assert.False(parameters.RawBodyData.ContainsKey("item_id")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + } +} diff --git a/src/Orb.Tests/Models/InvoiceLineItems/InvoiceLineItemCreateResponseTest.cs b/src/Orb.Tests/Models/InvoiceLineItems/InvoiceLineItemCreateResponseTest.cs new file mode 100644 index 00000000..760a7d84 --- /dev/null +++ b/src/Orb.Tests/Models/InvoiceLineItems/InvoiceLineItemCreateResponseTest.cs @@ -0,0 +1,1595 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.InvoiceLineItems; +using Models = Orb.Models; + +namespace Orb.Tests.Models.InvoiceLineItems; + +public class InvoiceLineItemCreateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceLineItemCreateResponse + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Models::Price expectedPrice = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustedSubtotal, model.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, model.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], model.Adjustments[i]); + } + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreditsApplied, model.CreditsApplied); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilter, model.Filter); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, model.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedSubLineItems.Count, model.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], model.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, model.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], model.TaxAmounts[i]); + } + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceLineItemCreateResponse + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceLineItemCreateResponse + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Models::Price expectedPrice = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustedSubtotal, deserialized.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, deserialized.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], deserialized.Adjustments[i]); + } + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreditsApplied, deserialized.CreditsApplied); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, deserialized.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedSubLineItems.Count, deserialized.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], deserialized.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, deserialized.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], deserialized.TaxAmounts[i]); + } + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceLineItemCreateResponse + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void MonetaryUsageDiscountValidationWorks() + { + Adjustment value = new( + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryAmountDiscountValidationWorks() + { + Adjustment value = new( + new Models::MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = Models::AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryPercentageDiscountValidationWorks() + { + Adjustment value = new( + new Models::MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMinimumValidationWorks() + { + Adjustment value = new( + new Models::MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMaximumValidationWorks() + { + Adjustment value = new( + new Models::MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryUsageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryAmountDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = Models::AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryPercentageDiscountSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMinimumSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMaximumSerializationRoundtripWorks() + { + Adjustment value = new( + new Models::MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = Models::MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class SubLineItemTest : TestBase +{ + [Fact] + public void MatrixValidationWorks() + { + SubLineItem value = new( + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + value.Validate(); + } + + [Fact] + public void TierValidationWorks() + { + SubLineItem value = new( + new Models::TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = Models::TierSubLineItemType.Tier, + } + ); + value.Validate(); + } + + [Fact] + public void OtherValidationWorks() + { + SubLineItem value = new( + new Models::OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = Models::OtherSubLineItemType.Null, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixSerializationRoundtripWorks() + { + SubLineItem value = new( + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TierSerializationRoundtripWorks() + { + SubLineItem value = new( + new Models::TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = Models::TierSubLineItemType.Tier, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void OtherSerializationRoundtripWorks() + { + SubLineItem value = new( + new Models::OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = Models::OtherSubLineItemType.Null, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/InvoiceTest.cs b/src/Orb.Tests/Models/InvoiceTest.cs new file mode 100644 index 00000000..866731d3 --- /dev/null +++ b/src/Orb.Tests/Models/InvoiceTest.cs @@ -0,0 +1,4488 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class InvoiceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string expectedID = "id"; + string expectedAmountDue = "8.00"; + InvoiceAutoCollection expectedAutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + List expectedCreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ]; + string expectedCurrency = "USD"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + List expectedCustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ]; + CustomerTaxID expectedCustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + JsonElement expectedDiscount = JsonSerializer.Deserialize("{}"); + List expectedDiscounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ]; + DateTimeOffset expectedDueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"); + DateTimeOffset expectedEligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedHostedInvoiceURL = "hosted_invoice_url"; + DateTimeOffset expectedInvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"); + string expectedInvoiceNumber = "JYEFHK-00001"; + string expectedInvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + ApiEnum expectedInvoiceSource = + InvoiceInvoiceSource.Subscription; + DateTimeOffset expectedIssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedIssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ]; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + string expectedMemo = "memo"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedPaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ]; + DateTimeOffset expectedPaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedPaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + ApiEnum expectedStatus = InvoiceStatus.Issued; + SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + string expectedSubtotal = "8.00"; + DateTimeOffset expectedSyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedTotal = "8.00"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedWillAutoIssue = true; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmountDue, model.AmountDue); + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedBillingAddress, model.BillingAddress); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNotes.Count, model.CreditNotes.Count); + for (int i = 0; i < expectedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreditNotes[i], model.CreditNotes[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal( + expectedCustomerBalanceTransactions.Count, + model.CustomerBalanceTransactions.Count + ); + for (int i = 0; i < expectedCustomerBalanceTransactions.Count; i++) + { + Assert.Equal( + expectedCustomerBalanceTransactions[i], + model.CustomerBalanceTransactions[i] + ); + } + Assert.Equal(expectedCustomerTaxID, model.CustomerTaxID); + Assert.True(JsonElement.DeepEquals(expectedDiscount, model.Discount)); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedDueDate, model.DueDate); + Assert.Equal(expectedEligibleToIssueAt, model.EligibleToIssueAt); + Assert.Equal(expectedHostedInvoiceURL, model.HostedInvoiceURL); + Assert.Equal(expectedInvoiceDate, model.InvoiceDate); + Assert.Equal(expectedInvoiceNumber, model.InvoiceNumber); + Assert.Equal(expectedInvoicePdf, model.InvoicePdf); + Assert.Equal(expectedInvoiceSource, model.InvoiceSource); + Assert.Equal(expectedIssueFailedAt, model.IssueFailedAt); + Assert.Equal(expectedIssuedAt, model.IssuedAt); + Assert.Equal(expectedLineItems.Count, model.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], model.LineItems[i]); + } + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPaidAt, model.PaidAt); + Assert.Equal(expectedPaymentAttempts.Count, model.PaymentAttempts.Count); + for (int i = 0; i < expectedPaymentAttempts.Count; i++) + { + Assert.Equal(expectedPaymentAttempts[i], model.PaymentAttempts[i]); + } + Assert.Equal(expectedPaymentFailedAt, model.PaymentFailedAt); + Assert.Equal(expectedPaymentStartedAt, model.PaymentStartedAt); + Assert.Equal(expectedScheduledIssueAt, model.ScheduledIssueAt); + Assert.Equal(expectedShippingAddress, model.ShippingAddress); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedSyncFailedAt, model.SyncFailedAt); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + Assert.Equal(expectedWillAutoIssue, model.WillAutoIssue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmountDue = "8.00"; + InvoiceAutoCollection expectedAutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + List expectedCreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ]; + string expectedCurrency = "USD"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + List expectedCustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ]; + CustomerTaxID expectedCustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + JsonElement expectedDiscount = JsonSerializer.Deserialize("{}"); + List expectedDiscounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ]; + DateTimeOffset expectedDueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"); + DateTimeOffset expectedEligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedHostedInvoiceURL = "hosted_invoice_url"; + DateTimeOffset expectedInvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"); + string expectedInvoiceNumber = "JYEFHK-00001"; + string expectedInvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + ApiEnum expectedInvoiceSource = + InvoiceInvoiceSource.Subscription; + DateTimeOffset expectedIssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedIssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ]; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + string expectedMemo = "memo"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedPaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ]; + DateTimeOffset expectedPaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedPaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + ApiEnum expectedStatus = InvoiceStatus.Issued; + SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + string expectedSubtotal = "8.00"; + DateTimeOffset expectedSyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedTotal = "8.00"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedWillAutoIssue = true; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmountDue, deserialized.AmountDue); + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedBillingAddress, deserialized.BillingAddress); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNotes.Count, deserialized.CreditNotes.Count); + for (int i = 0; i < expectedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreditNotes[i], deserialized.CreditNotes[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal( + expectedCustomerBalanceTransactions.Count, + deserialized.CustomerBalanceTransactions.Count + ); + for (int i = 0; i < expectedCustomerBalanceTransactions.Count; i++) + { + Assert.Equal( + expectedCustomerBalanceTransactions[i], + deserialized.CustomerBalanceTransactions[i] + ); + } + Assert.Equal(expectedCustomerTaxID, deserialized.CustomerTaxID); + Assert.True(JsonElement.DeepEquals(expectedDiscount, deserialized.Discount)); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedDueDate, deserialized.DueDate); + Assert.Equal(expectedEligibleToIssueAt, deserialized.EligibleToIssueAt); + Assert.Equal(expectedHostedInvoiceURL, deserialized.HostedInvoiceURL); + Assert.Equal(expectedInvoiceDate, deserialized.InvoiceDate); + Assert.Equal(expectedInvoiceNumber, deserialized.InvoiceNumber); + Assert.Equal(expectedInvoicePdf, deserialized.InvoicePdf); + Assert.Equal(expectedInvoiceSource, deserialized.InvoiceSource); + Assert.Equal(expectedIssueFailedAt, deserialized.IssueFailedAt); + Assert.Equal(expectedIssuedAt, deserialized.IssuedAt); + Assert.Equal(expectedLineItems.Count, deserialized.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], deserialized.LineItems[i]); + } + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPaidAt, deserialized.PaidAt); + Assert.Equal(expectedPaymentAttempts.Count, deserialized.PaymentAttempts.Count); + for (int i = 0; i < expectedPaymentAttempts.Count; i++) + { + Assert.Equal(expectedPaymentAttempts[i], deserialized.PaymentAttempts[i]); + } + Assert.Equal(expectedPaymentFailedAt, deserialized.PaymentFailedAt); + Assert.Equal(expectedPaymentStartedAt, deserialized.PaymentStartedAt); + Assert.Equal(expectedScheduledIssueAt, deserialized.ScheduledIssueAt); + Assert.Equal(expectedShippingAddress, deserialized.ShippingAddress); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedSyncFailedAt, deserialized.SyncFailedAt); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + Assert.Equal(expectedWillAutoIssue, deserialized.WillAutoIssue); + } + + [Fact] + public void Validation_Works() + { + var model = new Invoice + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + model.Validate(); + } +} + +public class InvoiceAutoCollectionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceAutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + bool expectedEnabled = true; + DateTimeOffset expectedNextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedNumAttempts = 0; + DateTimeOffset expectedPreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedEnabled, model.Enabled); + Assert.Equal(expectedNextAttemptAt, model.NextAttemptAt); + Assert.Equal(expectedNumAttempts, model.NumAttempts); + Assert.Equal(expectedPreviouslyAttemptedAt, model.PreviouslyAttemptedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceAutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceAutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedEnabled = true; + DateTimeOffset expectedNextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedNumAttempts = 0; + DateTimeOffset expectedPreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedEnabled, deserialized.Enabled); + Assert.Equal(expectedNextAttemptAt, deserialized.NextAttemptAt); + Assert.Equal(expectedNumAttempts, deserialized.NumAttempts); + Assert.Equal(expectedPreviouslyAttemptedAt, deserialized.PreviouslyAttemptedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceAutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class InvoiceCreditNoteTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceCreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string expectedID = "id"; + string expectedCreditNoteNumber = "credit_note_number"; + string expectedMemo = "memo"; + string expectedReason = "reason"; + string expectedTotal = "total"; + string expectedType = "type"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreditNoteNumber, model.CreditNoteNumber); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceCreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceCreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedCreditNoteNumber = "credit_note_number"; + string expectedMemo = "memo"; + string expectedReason = "reason"; + string expectedTotal = "total"; + string expectedType = "type"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreditNoteNumber, deserialized.CreditNoteNumber); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceCreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + model.Validate(); + } +} + +public class InvoiceCustomerBalanceTransactionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceCustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }; + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = + InvoiceCustomerBalanceTransactionAction.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = + InvoiceCustomerBalanceTransactionType.Increment; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAction, model.Action); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNote, model.CreditNote); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedInvoice, model.Invoice); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceCustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceCustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = + InvoiceCustomerBalanceTransactionAction.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = + InvoiceCustomerBalanceTransactionType.Increment; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAction, deserialized.Action); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNote, deserialized.CreditNote); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedInvoice, deserialized.Invoice); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceCustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }; + + model.Validate(); + } +} + +public class InvoiceCustomerBalanceTransactionActionTest : TestBase +{ + [Theory] + [InlineData(InvoiceCustomerBalanceTransactionAction.AppliedToInvoice)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ManualAdjustment)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ProratedRefund)] + [InlineData(InvoiceCustomerBalanceTransactionAction.RevertProratedRefund)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ReturnFromVoiding)] + [InlineData(InvoiceCustomerBalanceTransactionAction.CreditNoteApplied)] + [InlineData(InvoiceCustomerBalanceTransactionAction.CreditNoteVoided)] + [InlineData(InvoiceCustomerBalanceTransactionAction.OverpaymentRefund)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ExternalPayment)] + [InlineData(InvoiceCustomerBalanceTransactionAction.SmallInvoiceCarryover)] + public void Validation_Works(InvoiceCustomerBalanceTransactionAction rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(InvoiceCustomerBalanceTransactionAction.AppliedToInvoice)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ManualAdjustment)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ProratedRefund)] + [InlineData(InvoiceCustomerBalanceTransactionAction.RevertProratedRefund)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ReturnFromVoiding)] + [InlineData(InvoiceCustomerBalanceTransactionAction.CreditNoteApplied)] + [InlineData(InvoiceCustomerBalanceTransactionAction.CreditNoteVoided)] + [InlineData(InvoiceCustomerBalanceTransactionAction.OverpaymentRefund)] + [InlineData(InvoiceCustomerBalanceTransactionAction.ExternalPayment)] + [InlineData(InvoiceCustomerBalanceTransactionAction.SmallInvoiceCarryover)] + public void SerializationRoundtrip_Works(InvoiceCustomerBalanceTransactionAction rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceCustomerBalanceTransactionTypeTest : TestBase +{ + [Theory] + [InlineData(InvoiceCustomerBalanceTransactionType.Increment)] + [InlineData(InvoiceCustomerBalanceTransactionType.Decrement)] + public void Validation_Works(InvoiceCustomerBalanceTransactionType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(InvoiceCustomerBalanceTransactionType.Increment)] + [InlineData(InvoiceCustomerBalanceTransactionType.Decrement)] + public void SerializationRoundtrip_Works(InvoiceCustomerBalanceTransactionType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceInvoiceSourceTest : TestBase +{ + [Theory] + [InlineData(InvoiceInvoiceSource.Subscription)] + [InlineData(InvoiceInvoiceSource.Partial)] + [InlineData(InvoiceInvoiceSource.OneOff)] + public void Validation_Works(InvoiceInvoiceSource rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(InvoiceInvoiceSource.Subscription)] + [InlineData(InvoiceInvoiceSource.Partial)] + [InlineData(InvoiceInvoiceSource.OneOff)] + public void SerializationRoundtrip_Works(InvoiceInvoiceSource rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceLineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustedSubtotal, model.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, model.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], model.Adjustments[i]); + } + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreditsApplied, model.CreditsApplied); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilter, model.Filter); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, model.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedSubLineItems.Count, model.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], model.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, model.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], model.TaxAmounts[i]); + } + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustedSubtotal, deserialized.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, deserialized.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], deserialized.Adjustments[i]); + } + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreditsApplied, deserialized.CreditsApplied); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, deserialized.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedSubLineItems.Count, deserialized.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], deserialized.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, deserialized.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], deserialized.TaxAmounts[i]); + } + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } +} + +public class InvoiceLineItemAdjustmentTest : TestBase +{ + [Fact] + public void MonetaryUsageDiscountValidationWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryAmountDiscountValidationWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryPercentageDiscountValidationWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMinimumValidationWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMaximumValidationWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryUsageDiscountSerializationRoundtripWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryAmountDiscountSerializationRoundtripWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryPercentageDiscountSerializationRoundtripWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMinimumSerializationRoundtripWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMaximumSerializationRoundtripWorks() + { + InvoiceLineItemAdjustment value = new( + new MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceLineItemSubLineItemTest : TestBase +{ + [Fact] + public void MatrixValidationWorks() + { + InvoiceLineItemSubLineItem value = new( + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + value.Validate(); + } + + [Fact] + public void TierValidationWorks() + { + InvoiceLineItemSubLineItem value = new( + new TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + } + ); + value.Validate(); + } + + [Fact] + public void OtherValidationWorks() + { + InvoiceLineItemSubLineItem value = new( + new OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixSerializationRoundtripWorks() + { + InvoiceLineItemSubLineItem value = new( + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TierSerializationRoundtripWorks() + { + InvoiceLineItemSubLineItem value = new( + new TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void OtherSerializationRoundtripWorks() + { + InvoiceLineItemSubLineItem value = new( + new OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class InvoicePaymentAttemptTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoicePaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedPaymentProvider = + InvoicePaymentAttemptPaymentProvider.Stripe; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + bool expectedSucceeded = true; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedPaymentProvider, model.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, model.PaymentProviderID); + Assert.Equal(expectedReceiptPdf, model.ReceiptPdf); + Assert.Equal(expectedSucceeded, model.Succeeded); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoicePaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoicePaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedPaymentProvider = + InvoicePaymentAttemptPaymentProvider.Stripe; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + bool expectedSucceeded = true; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedPaymentProvider, deserialized.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, deserialized.PaymentProviderID); + Assert.Equal(expectedReceiptPdf, deserialized.ReceiptPdf); + Assert.Equal(expectedSucceeded, deserialized.Succeeded); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoicePaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + model.Validate(); + } +} + +public class InvoicePaymentAttemptPaymentProviderTest : TestBase +{ + [Theory] + [InlineData(InvoicePaymentAttemptPaymentProvider.Stripe)] + public void Validation_Works(InvoicePaymentAttemptPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(InvoicePaymentAttemptPaymentProvider.Stripe)] + public void SerializationRoundtrip_Works(InvoicePaymentAttemptPaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceStatusTest : TestBase +{ + [Theory] + [InlineData(InvoiceStatus.Issued)] + [InlineData(InvoiceStatus.Paid)] + [InlineData(InvoiceStatus.Synced)] + [InlineData(InvoiceStatus.Void)] + [InlineData(InvoiceStatus.Draft)] + public void Validation_Works(InvoiceStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(InvoiceStatus.Issued)] + [InlineData(InvoiceStatus.Paid)] + [InlineData(InvoiceStatus.Synced)] + [InlineData(InvoiceStatus.Void)] + [InlineData(InvoiceStatus.Draft)] + public void SerializationRoundtrip_Works(InvoiceStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/InvoiceTinyTest.cs b/src/Orb.Tests/Models/InvoiceTinyTest.cs new file mode 100644 index 00000000..7d421a34 --- /dev/null +++ b/src/Orb.Tests/Models/InvoiceTinyTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class InvoiceTinyTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceTiny { ID = "gXcsPTVyC4YZa3Sc" }; + + string expectedID = "gXcsPTVyC4YZa3Sc"; + + Assert.Equal(expectedID, model.ID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceTiny { ID = "gXcsPTVyC4YZa3Sc" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceTiny { ID = "gXcsPTVyC4YZa3Sc" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "gXcsPTVyC4YZa3Sc"; + + Assert.Equal(expectedID, deserialized.ID); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceTiny { ID = "gXcsPTVyC4YZa3Sc" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceCreateParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceCreateParamsTest.cs new file mode 100644 index 00000000..2d9572d8 --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceCreateParamsTest.cs @@ -0,0 +1,512 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Invoices; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceCreateParams + { + Currency = "USD", + InvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ], + CustomerID = "4khy3nwzktxv7", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DueDate = "2023-09-22", + ExternalCustomerID = "external-customer-id", + Memo = "An optional memo for my invoice.", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + WillAutoIssue = false, + }; + + string expectedCurrency = "USD"; + DateTimeOffset expectedInvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ]; + string expectedCustomerID = "4khy3nwzktxv7"; + Models::SharedDiscount expectedDiscount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + DueDate expectedDueDate = "2023-09-22"; + string expectedExternalCustomerID = "external-customer-id"; + string expectedMemo = "An optional memo for my invoice."; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + long expectedNetTerms = 0; + bool expectedWillAutoIssue = false; + + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedInvoiceDate, parameters.InvoiceDate); + Assert.Equal(expectedLineItems.Count, parameters.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], parameters.LineItems[i]); + } + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedDiscount, parameters.Discount); + Assert.Equal(expectedDueDate, parameters.DueDate); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedMemo, parameters.Memo); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedNetTerms, parameters.NetTerms); + Assert.Equal(expectedWillAutoIssue, parameters.WillAutoIssue); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceCreateParams + { + Currency = "USD", + InvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ], + CustomerID = "4khy3nwzktxv7", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DueDate = "2023-09-22", + ExternalCustomerID = "external-customer-id", + Memo = "An optional memo for my invoice.", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + }; + + Assert.Null(parameters.WillAutoIssue); + Assert.False(parameters.RawBodyData.ContainsKey("will_auto_issue")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new InvoiceCreateParams + { + Currency = "USD", + InvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ], + CustomerID = "4khy3nwzktxv7", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + DueDate = "2023-09-22", + ExternalCustomerID = "external-customer-id", + Memo = "An optional memo for my invoice.", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + + // Null should be interpreted as omitted for these properties + WillAutoIssue = null, + }; + + Assert.Null(parameters.WillAutoIssue); + Assert.False(parameters.RawBodyData.ContainsKey("will_auto_issue")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceCreateParams + { + Currency = "USD", + InvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ], + WillAutoIssue = false, + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.Discount); + Assert.False(parameters.RawBodyData.ContainsKey("discount")); + Assert.Null(parameters.DueDate); + Assert.False(parameters.RawBodyData.ContainsKey("due_date")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Memo); + Assert.False(parameters.RawBodyData.ContainsKey("memo")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new InvoiceCreateParams + { + Currency = "USD", + InvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ], + WillAutoIssue = false, + + CustomerID = null, + Discount = null, + DueDate = null, + ExternalCustomerID = null, + Memo = null, + Metadata = null, + NetTerms = null, + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.Discount); + Assert.False(parameters.RawBodyData.ContainsKey("discount")); + Assert.Null(parameters.DueDate); + Assert.False(parameters.RawBodyData.ContainsKey("due_date")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Memo); + Assert.False(parameters.RawBodyData.ContainsKey("memo")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + } +} + +public class LineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new LineItem + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + string expectedEndDate = "2023-09-22"; + string expectedItemID = "4khy3nwzktxv7"; + ApiEnum expectedModelType = ModelType.Unit; + string expectedName = "Line Item Name"; + double expectedQuantity = 1; + string expectedStartDate = "2023-09-22"; + Models::UnitConfig expectedUnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }; + + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedUnitConfig, model.UnitConfig); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new LineItem + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new LineItem + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedEndDate = "2023-09-22"; + string expectedItemID = "4khy3nwzktxv7"; + ApiEnum expectedModelType = ModelType.Unit; + string expectedName = "Line Item Name"; + double expectedQuantity = 1; + string expectedStartDate = "2023-09-22"; + Models::UnitConfig expectedUnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }; + + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedUnitConfig, deserialized.UnitConfig); + } + + [Fact] + public void Validation_Works() + { + var model = new LineItem + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + model.Validate(); + } +} + +public class ModelTypeTest : TestBase +{ + [Theory] + [InlineData(ModelType.Unit)] + public void Validation_Works(ModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ModelType.Unit)] + public void SerializationRoundtrip_Works(ModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class DueDateTest : TestBase +{ + [Fact] + public void DateValidationWorks() + { + DueDate value = new("2019-12-27"); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + DueDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + DueDate value = new("2019-12-27"); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + DueDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceFetchParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceFetchParamsTest.cs new file mode 100644 index 00000000..b8cef220 --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceFetchParams { InvoiceID = "invoice_id" }; + + string expectedInvoiceID = "invoice_id"; + + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceFetchUpcomingParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceFetchUpcomingParamsTest.cs new file mode 100644 index 00000000..96de9d51 --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceFetchUpcomingParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceFetchUpcomingParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceFetchUpcomingParams { SubscriptionID = "subscription_id" }; + + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceFetchUpcomingResponseTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceFetchUpcomingResponseTest.cs new file mode 100644 index 00000000..50cd38e6 --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceFetchUpcomingResponseTest.cs @@ -0,0 +1,4489 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Invoices = Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceFetchUpcomingResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponse + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Invoices::InvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Invoices::InvoiceFetchUpcomingResponseStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TargetDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string expectedID = "id"; + string expectedAmountDue = "8.00"; + Invoices::AutoCollection expectedAutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + List expectedCreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ]; + string expectedCurrency = "USD"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + List expectedCustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }, + ]; + CustomerTaxID expectedCustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + JsonElement expectedDiscount = JsonSerializer.Deserialize("{}"); + List expectedDiscounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ]; + DateTimeOffset expectedDueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"); + DateTimeOffset expectedEligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedHostedInvoiceURL = "hosted_invoice_url"; + string expectedInvoiceNumber = "JYEFHK-00001"; + string expectedInvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + ApiEnum expectedInvoiceSource = + Invoices::InvoiceSource.Subscription; + DateTimeOffset expectedIssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedIssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ]; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + string expectedMemo = "memo"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedPaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ]; + DateTimeOffset expectedPaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedPaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + ApiEnum expectedStatus = + Invoices::InvoiceFetchUpcomingResponseStatus.Issued; + SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + string expectedSubtotal = "8.00"; + DateTimeOffset expectedSyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTargetDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"); + string expectedTotal = "8.00"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedWillAutoIssue = true; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmountDue, model.AmountDue); + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal(expectedBillingAddress, model.BillingAddress); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNotes.Count, model.CreditNotes.Count); + for (int i = 0; i < expectedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreditNotes[i], model.CreditNotes[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal( + expectedCustomerBalanceTransactions.Count, + model.CustomerBalanceTransactions.Count + ); + for (int i = 0; i < expectedCustomerBalanceTransactions.Count; i++) + { + Assert.Equal( + expectedCustomerBalanceTransactions[i], + model.CustomerBalanceTransactions[i] + ); + } + Assert.Equal(expectedCustomerTaxID, model.CustomerTaxID); + Assert.True(JsonElement.DeepEquals(expectedDiscount, model.Discount)); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedDueDate, model.DueDate); + Assert.Equal(expectedEligibleToIssueAt, model.EligibleToIssueAt); + Assert.Equal(expectedHostedInvoiceURL, model.HostedInvoiceURL); + Assert.Equal(expectedInvoiceNumber, model.InvoiceNumber); + Assert.Equal(expectedInvoicePdf, model.InvoicePdf); + Assert.Equal(expectedInvoiceSource, model.InvoiceSource); + Assert.Equal(expectedIssueFailedAt, model.IssueFailedAt); + Assert.Equal(expectedIssuedAt, model.IssuedAt); + Assert.Equal(expectedLineItems.Count, model.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], model.LineItems[i]); + } + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPaidAt, model.PaidAt); + Assert.Equal(expectedPaymentAttempts.Count, model.PaymentAttempts.Count); + for (int i = 0; i < expectedPaymentAttempts.Count; i++) + { + Assert.Equal(expectedPaymentAttempts[i], model.PaymentAttempts[i]); + } + Assert.Equal(expectedPaymentFailedAt, model.PaymentFailedAt); + Assert.Equal(expectedPaymentStartedAt, model.PaymentStartedAt); + Assert.Equal(expectedScheduledIssueAt, model.ScheduledIssueAt); + Assert.Equal(expectedShippingAddress, model.ShippingAddress); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedSyncFailedAt, model.SyncFailedAt); + Assert.Equal(expectedTargetDate, model.TargetDate); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + Assert.Equal(expectedWillAutoIssue, model.WillAutoIssue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponse + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Invoices::InvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Invoices::InvoiceFetchUpcomingResponseStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TargetDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponse + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Invoices::InvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Invoices::InvoiceFetchUpcomingResponseStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TargetDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmountDue = "8.00"; + Invoices::AutoCollection expectedAutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Address expectedBillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + List expectedCreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ]; + string expectedCurrency = "USD"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + List expectedCustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }, + ]; + CustomerTaxID expectedCustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }; + JsonElement expectedDiscount = JsonSerializer.Deserialize("{}"); + List expectedDiscounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ]; + DateTimeOffset expectedDueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"); + DateTimeOffset expectedEligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedHostedInvoiceURL = "hosted_invoice_url"; + string expectedInvoiceNumber = "JYEFHK-00001"; + string expectedInvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + ApiEnum expectedInvoiceSource = + Invoices::InvoiceSource.Subscription; + DateTimeOffset expectedIssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedIssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedLineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ]; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + string expectedMemo = "memo"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedPaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedPaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ]; + DateTimeOffset expectedPaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedPaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Address expectedShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }; + ApiEnum expectedStatus = + Invoices::InvoiceFetchUpcomingResponseStatus.Issued; + SubscriptionMinified expectedSubscription = new("VDGsT23osdLb84KD"); + string expectedSubtotal = "8.00"; + DateTimeOffset expectedSyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTargetDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"); + string expectedTotal = "8.00"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedWillAutoIssue = true; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmountDue, deserialized.AmountDue); + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal(expectedBillingAddress, deserialized.BillingAddress); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNotes.Count, deserialized.CreditNotes.Count); + for (int i = 0; i < expectedCreditNotes.Count; i++) + { + Assert.Equal(expectedCreditNotes[i], deserialized.CreditNotes[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal( + expectedCustomerBalanceTransactions.Count, + deserialized.CustomerBalanceTransactions.Count + ); + for (int i = 0; i < expectedCustomerBalanceTransactions.Count; i++) + { + Assert.Equal( + expectedCustomerBalanceTransactions[i], + deserialized.CustomerBalanceTransactions[i] + ); + } + Assert.Equal(expectedCustomerTaxID, deserialized.CustomerTaxID); + Assert.True(JsonElement.DeepEquals(expectedDiscount, deserialized.Discount)); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedDueDate, deserialized.DueDate); + Assert.Equal(expectedEligibleToIssueAt, deserialized.EligibleToIssueAt); + Assert.Equal(expectedHostedInvoiceURL, deserialized.HostedInvoiceURL); + Assert.Equal(expectedInvoiceNumber, deserialized.InvoiceNumber); + Assert.Equal(expectedInvoicePdf, deserialized.InvoicePdf); + Assert.Equal(expectedInvoiceSource, deserialized.InvoiceSource); + Assert.Equal(expectedIssueFailedAt, deserialized.IssueFailedAt); + Assert.Equal(expectedIssuedAt, deserialized.IssuedAt); + Assert.Equal(expectedLineItems.Count, deserialized.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], deserialized.LineItems[i]); + } + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPaidAt, deserialized.PaidAt); + Assert.Equal(expectedPaymentAttempts.Count, deserialized.PaymentAttempts.Count); + for (int i = 0; i < expectedPaymentAttempts.Count; i++) + { + Assert.Equal(expectedPaymentAttempts[i], deserialized.PaymentAttempts[i]); + } + Assert.Equal(expectedPaymentFailedAt, deserialized.PaymentFailedAt); + Assert.Equal(expectedPaymentStartedAt, deserialized.PaymentStartedAt); + Assert.Equal(expectedScheduledIssueAt, deserialized.ScheduledIssueAt); + Assert.Equal(expectedShippingAddress, deserialized.ShippingAddress); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedSyncFailedAt, deserialized.SyncFailedAt); + Assert.Equal(expectedTargetDate, deserialized.TargetDate); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + Assert.Equal(expectedWillAutoIssue, deserialized.WillAutoIssue); + } + + [Fact] + public void Validation_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponse + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Invoices::InvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Invoices::InvoiceFetchUpcomingResponseStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TargetDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }; + + model.Validate(); + } +} + +public class AutoCollectionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoices::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + bool expectedEnabled = true; + DateTimeOffset expectedNextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedNumAttempts = 0; + DateTimeOffset expectedPreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedEnabled, model.Enabled); + Assert.Equal(expectedNextAttemptAt, model.NextAttemptAt); + Assert.Equal(expectedNumAttempts, model.NumAttempts); + Assert.Equal(expectedPreviouslyAttemptedAt, model.PreviouslyAttemptedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoices::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoices::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedEnabled = true; + DateTimeOffset expectedNextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedNumAttempts = 0; + DateTimeOffset expectedPreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedEnabled, deserialized.Enabled); + Assert.Equal(expectedNextAttemptAt, deserialized.NextAttemptAt); + Assert.Equal(expectedNumAttempts, deserialized.NumAttempts); + Assert.Equal(expectedPreviouslyAttemptedAt, deserialized.PreviouslyAttemptedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new Invoices::AutoCollection + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class CreditNoteTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoices::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string expectedID = "id"; + string expectedCreditNoteNumber = "credit_note_number"; + string expectedMemo = "memo"; + string expectedReason = "reason"; + string expectedTotal = "total"; + string expectedType = "type"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreditNoteNumber, model.CreditNoteNumber); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoices::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoices::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedCreditNoteNumber = "credit_note_number"; + string expectedMemo = "memo"; + string expectedReason = "reason"; + string expectedTotal = "total"; + string expectedType = "type"; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreditNoteNumber, deserialized.CreditNoteNumber); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new Invoices::CreditNote + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }; + + model.Validate(); + } +} + +public class CustomerBalanceTransactionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoices::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }; + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = Invoices::Action.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = Invoices::Type.Increment; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAction, model.Action); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNote, model.CreditNote); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedEndingBalance, model.EndingBalance); + Assert.Equal(expectedInvoice, model.Invoice); + Assert.Equal(expectedStartingBalance, model.StartingBalance); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoices::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoices::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "cgZa3SXcsPTVyC4Y"; + ApiEnum expectedAction = Invoices::Action.AppliedToInvoice; + string expectedAmount = "11.00"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"); + CreditNoteTiny expectedCreditNote = new("id"); + string expectedDescription = "An optional description"; + string expectedEndingBalance = "22.00"; + InvoiceTiny expectedInvoice = new("gXcsPTVyC4YZa3Sc"); + string expectedStartingBalance = "33.00"; + ApiEnum expectedType = Invoices::Type.Increment; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAction, deserialized.Action); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNote, deserialized.CreditNote); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedEndingBalance, deserialized.EndingBalance); + Assert.Equal(expectedInvoice, deserialized.Invoice); + Assert.Equal(expectedStartingBalance, deserialized.StartingBalance); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new Invoices::CustomerBalanceTransaction + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Invoices::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Invoices::Type.Increment, + }; + + model.Validate(); + } +} + +public class ActionTest : TestBase +{ + [Theory] + [InlineData(Invoices::Action.AppliedToInvoice)] + [InlineData(Invoices::Action.ManualAdjustment)] + [InlineData(Invoices::Action.ProratedRefund)] + [InlineData(Invoices::Action.RevertProratedRefund)] + [InlineData(Invoices::Action.ReturnFromVoiding)] + [InlineData(Invoices::Action.CreditNoteApplied)] + [InlineData(Invoices::Action.CreditNoteVoided)] + [InlineData(Invoices::Action.OverpaymentRefund)] + [InlineData(Invoices::Action.ExternalPayment)] + [InlineData(Invoices::Action.SmallInvoiceCarryover)] + public void Validation_Works(Invoices::Action rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Invoices::Action.AppliedToInvoice)] + [InlineData(Invoices::Action.ManualAdjustment)] + [InlineData(Invoices::Action.ProratedRefund)] + [InlineData(Invoices::Action.RevertProratedRefund)] + [InlineData(Invoices::Action.ReturnFromVoiding)] + [InlineData(Invoices::Action.CreditNoteApplied)] + [InlineData(Invoices::Action.CreditNoteVoided)] + [InlineData(Invoices::Action.OverpaymentRefund)] + [InlineData(Invoices::Action.ExternalPayment)] + [InlineData(Invoices::Action.SmallInvoiceCarryover)] + public void SerializationRoundtrip_Works(Invoices::Action rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TypeTest : TestBase +{ + [Theory] + [InlineData(Invoices::Type.Increment)] + [InlineData(Invoices::Type.Decrement)] + public void Validation_Works(Invoices::Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Invoices::Type.Increment)] + [InlineData(Invoices::Type.Decrement)] + public void SerializationRoundtrip_Works(Invoices::Type rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceSourceTest : TestBase +{ + [Theory] + [InlineData(Invoices::InvoiceSource.Subscription)] + [InlineData(Invoices::InvoiceSource.Partial)] + [InlineData(Invoices::InvoiceSource.OneOff)] + public void Validation_Works(Invoices::InvoiceSource rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Invoices::InvoiceSource.Subscription)] + [InlineData(Invoices::InvoiceSource.Partial)] + [InlineData(Invoices::InvoiceSource.OneOff)] + public void SerializationRoundtrip_Works(Invoices::InvoiceSource rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceFetchUpcomingResponseLineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponseLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustedSubtotal, model.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, model.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], model.Adjustments[i]); + } + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreditsApplied, model.CreditsApplied); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilter, model.Filter); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, model.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedSubLineItems.Count, model.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], model.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, model.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], model.TaxAmounts[i]); + } + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponseLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponseLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAdjustedSubtotal = "5.00"; + List expectedAdjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + string expectedAmount = "7.00"; + string expectedCreditsApplied = "6.00"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + string expectedFilter = "filter"; + string expectedGrouping = "grouping"; + string expectedName = "Fixed Fee"; + string expectedPartiallyInvoicedAmount = "4.00"; + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + double expectedQuantity = 1; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"); + List expectedSubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ]; + string expectedSubtotal = "9.00"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustedSubtotal, deserialized.AdjustedSubtotal); + Assert.Equal(expectedAdjustments.Count, deserialized.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], deserialized.Adjustments[i]); + } + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreditsApplied, deserialized.CreditsApplied); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPartiallyInvoicedAmount, deserialized.PartiallyInvoicedAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedSubLineItems.Count, deserialized.SubLineItems.Count); + for (int i = 0; i < expectedSubLineItems.Count; i++) + { + Assert.Equal(expectedSubLineItems[i], deserialized.SubLineItems[i]); + } + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, deserialized.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], deserialized.TaxAmounts[i]); + } + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Invoices::InvoiceFetchUpcomingResponseLineItem + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void MonetaryUsageDiscountValidationWorks() + { + Invoices::Adjustment value = new( + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryAmountDiscountValidationWorks() + { + Invoices::Adjustment value = new( + new MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryPercentageDiscountValidationWorks() + { + Invoices::Adjustment value = new( + new MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMinimumValidationWorks() + { + Invoices::Adjustment value = new( + new MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryMaximumValidationWorks() + { + Invoices::Adjustment value = new( + new MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void MonetaryUsageDiscountSerializationRoundtripWorks() + { + Invoices::Adjustment value = new( + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryAmountDiscountSerializationRoundtripWorks() + { + Invoices::Adjustment value = new( + new MonetaryAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryPercentageDiscountSerializationRoundtripWorks() + { + Invoices::Adjustment value = new( + new MonetaryPercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMinimumSerializationRoundtripWorks() + { + Invoices::Adjustment value = new( + new MonetaryMinimumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MonetaryMaximumSerializationRoundtripWorks() + { + Invoices::Adjustment value = new( + new MonetaryMaximumAdjustment() + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class SubLineItemTest : TestBase +{ + [Fact] + public void MatrixValidationWorks() + { + Invoices::SubLineItem value = new( + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + value.Validate(); + } + + [Fact] + public void TierValidationWorks() + { + Invoices::SubLineItem value = new( + new TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + } + ); + value.Validate(); + } + + [Fact] + public void OtherValidationWorks() + { + Invoices::SubLineItem value = new( + new OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixSerializationRoundtripWorks() + { + Invoices::SubLineItem value = new( + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TierSerializationRoundtripWorks() + { + Invoices::SubLineItem value = new( + new TierSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void OtherSerializationRoundtripWorks() + { + Invoices::SubLineItem value = new( + new OtherSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PaymentAttemptTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Invoices::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedPaymentProvider = + Invoices::PaymentProvider.Stripe; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + bool expectedSucceeded = true; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedPaymentProvider, model.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, model.PaymentProviderID); + Assert.Equal(expectedReceiptPdf, model.ReceiptPdf); + Assert.Equal(expectedSucceeded, model.Succeeded); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Invoices::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Invoices::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedPaymentProvider = + Invoices::PaymentProvider.Stripe; + string expectedPaymentProviderID = "payment_provider_id"; + string expectedReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb"; + bool expectedSucceeded = true; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedPaymentProvider, deserialized.PaymentProvider); + Assert.Equal(expectedPaymentProviderID, deserialized.PaymentProviderID); + Assert.Equal(expectedReceiptPdf, deserialized.ReceiptPdf); + Assert.Equal(expectedSucceeded, deserialized.Succeeded); + } + + [Fact] + public void Validation_Works() + { + var model = new Invoices::PaymentAttempt + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Invoices::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }; + + model.Validate(); + } +} + +public class PaymentProviderTest : TestBase +{ + [Theory] + [InlineData(Invoices::PaymentProvider.Stripe)] + public void Validation_Works(Invoices::PaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Invoices::PaymentProvider.Stripe)] + public void SerializationRoundtrip_Works(Invoices::PaymentProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceFetchUpcomingResponseStatusTest : TestBase +{ + [Theory] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Issued)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Paid)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Synced)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Void)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Draft)] + public void Validation_Works(Invoices::InvoiceFetchUpcomingResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Issued)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Paid)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Synced)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Void)] + [InlineData(Invoices::InvoiceFetchUpcomingResponseStatus.Draft)] + public void SerializationRoundtrip_Works(Invoices::InvoiceFetchUpcomingResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceIssueParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceIssueParamsTest.cs new file mode 100644 index 00000000..b23372fa --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceIssueParamsTest.cs @@ -0,0 +1,42 @@ +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceIssueParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceIssueParams { InvoiceID = "invoice_id", Synchronous = true }; + + string expectedInvoiceID = "invoice_id"; + bool expectedSynchronous = true; + + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + Assert.Equal(expectedSynchronous, parameters.Synchronous); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceIssueParams { InvoiceID = "invoice_id" }; + + Assert.Null(parameters.Synchronous); + Assert.False(parameters.RawBodyData.ContainsKey("synchronous")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new InvoiceIssueParams + { + InvoiceID = "invoice_id", + + // Null should be interpreted as omitted for these properties + Synchronous = null, + }; + + Assert.Null(parameters.Synchronous); + Assert.False(parameters.RawBodyData.ContainsKey("synchronous")); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceListPageResponseTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceListPageResponseTest.cs new file mode 100644 index 00000000..f99c9fec --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceListPageResponseTest.cs @@ -0,0 +1,2113 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new InvoiceListPageResponse + { + Data = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new InvoiceListPageResponse + { + Data = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new InvoiceListPageResponse + { + Data = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new InvoiceListPageResponse + { + Data = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceListParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceListParamsTest.cs new file mode 100644 index 00000000..c2b4d9ef --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceListParamsTest.cs @@ -0,0 +1,374 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceListParams + { + Amount = "amount", + AmountGt = "amount[gt]", + AmountLt = "amount[lt]", + Cursor = "cursor", + CustomerID = "customer_id", + DateType = DateType.DueDate, + DueDate = "2019-12-27", + DueDateWindow = "due_date_window", + DueDateGt = "2019-12-27", + DueDateLt = "2019-12-27", + ExternalCustomerID = "external_customer_id", + InvoiceDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IsRecurring = true, + Limit = 1, + Status = [Status.Draft], + SubscriptionID = "subscription_id", + }; + + string expectedAmount = "amount"; + string expectedAmountGt = "amount[gt]"; + string expectedAmountLt = "amount[lt]"; + string expectedCursor = "cursor"; + string expectedCustomerID = "customer_id"; + ApiEnum expectedDateType = DateType.DueDate; + string expectedDueDate = "2019-12-27"; + string expectedDueDateWindow = "due_date_window"; + string expectedDueDateGt = "2019-12-27"; + string expectedDueDateLt = "2019-12-27"; + string expectedExternalCustomerID = "external_customer_id"; + DateTimeOffset expectedInvoiceDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedInvoiceDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedInvoiceDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedInvoiceDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + bool expectedIsRecurring = true; + long expectedLimit = 1; + List> expectedStatus = [Status.Draft]; + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedAmount, parameters.Amount); + Assert.Equal(expectedAmountGt, parameters.AmountGt); + Assert.Equal(expectedAmountLt, parameters.AmountLt); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedDateType, parameters.DateType); + Assert.Equal(expectedDueDate, parameters.DueDate); + Assert.Equal(expectedDueDateWindow, parameters.DueDateWindow); + Assert.Equal(expectedDueDateGt, parameters.DueDateGt); + Assert.Equal(expectedDueDateLt, parameters.DueDateLt); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedInvoiceDateGt, parameters.InvoiceDateGt); + Assert.Equal(expectedInvoiceDateGte, parameters.InvoiceDateGte); + Assert.Equal(expectedInvoiceDateLt, parameters.InvoiceDateLt); + Assert.Equal(expectedInvoiceDateLte, parameters.InvoiceDateLte); + Assert.Equal(expectedIsRecurring, parameters.IsRecurring); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.NotNull(parameters.Status); + Assert.Equal(expectedStatus.Count, parameters.Status.Count); + for (int i = 0; i < expectedStatus.Count; i++) + { + Assert.Equal(expectedStatus[i], parameters.Status[i]); + } + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceListParams + { + Amount = "amount", + AmountGt = "amount[gt]", + AmountLt = "amount[lt]", + Cursor = "cursor", + CustomerID = "customer_id", + DateType = DateType.DueDate, + DueDate = "2019-12-27", + DueDateWindow = "due_date_window", + DueDateGt = "2019-12-27", + DueDateLt = "2019-12-27", + ExternalCustomerID = "external_customer_id", + InvoiceDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IsRecurring = true, + Status = [Status.Draft], + SubscriptionID = "subscription_id", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new InvoiceListParams + { + Amount = "amount", + AmountGt = "amount[gt]", + AmountLt = "amount[lt]", + Cursor = "cursor", + CustomerID = "customer_id", + DateType = DateType.DueDate, + DueDate = "2019-12-27", + DueDateWindow = "due_date_window", + DueDateGt = "2019-12-27", + DueDateLt = "2019-12-27", + ExternalCustomerID = "external_customer_id", + InvoiceDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + InvoiceDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IsRecurring = true, + Status = [Status.Draft], + SubscriptionID = "subscription_id", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceListParams { Limit = 1 }; + + Assert.Null(parameters.Amount); + Assert.False(parameters.RawQueryData.ContainsKey("amount")); + Assert.Null(parameters.AmountGt); + Assert.False(parameters.RawQueryData.ContainsKey("amount[gt]")); + Assert.Null(parameters.AmountLt); + Assert.False(parameters.RawQueryData.ContainsKey("amount[lt]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("customer_id")); + Assert.Null(parameters.DateType); + Assert.False(parameters.RawQueryData.ContainsKey("date_type")); + Assert.Null(parameters.DueDate); + Assert.False(parameters.RawQueryData.ContainsKey("due_date")); + Assert.Null(parameters.DueDateWindow); + Assert.False(parameters.RawQueryData.ContainsKey("due_date_window")); + Assert.Null(parameters.DueDateGt); + Assert.False(parameters.RawQueryData.ContainsKey("due_date[gt]")); + Assert.Null(parameters.DueDateLt); + Assert.False(parameters.RawQueryData.ContainsKey("due_date[lt]")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("external_customer_id")); + Assert.Null(parameters.InvoiceDateGt); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[gt]")); + Assert.Null(parameters.InvoiceDateGte); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[gte]")); + Assert.Null(parameters.InvoiceDateLt); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[lt]")); + Assert.Null(parameters.InvoiceDateLte); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[lte]")); + Assert.Null(parameters.IsRecurring); + Assert.False(parameters.RawQueryData.ContainsKey("is_recurring")); + Assert.Null(parameters.Status); + Assert.False(parameters.RawQueryData.ContainsKey("status")); + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new InvoiceListParams + { + Limit = 1, + + Amount = null, + AmountGt = null, + AmountLt = null, + Cursor = null, + CustomerID = null, + DateType = null, + DueDate = null, + DueDateWindow = null, + DueDateGt = null, + DueDateLt = null, + ExternalCustomerID = null, + InvoiceDateGt = null, + InvoiceDateGte = null, + InvoiceDateLt = null, + InvoiceDateLte = null, + IsRecurring = null, + Status = null, + SubscriptionID = null, + }; + + Assert.Null(parameters.Amount); + Assert.False(parameters.RawQueryData.ContainsKey("amount")); + Assert.Null(parameters.AmountGt); + Assert.False(parameters.RawQueryData.ContainsKey("amount[gt]")); + Assert.Null(parameters.AmountLt); + Assert.False(parameters.RawQueryData.ContainsKey("amount[lt]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("customer_id")); + Assert.Null(parameters.DateType); + Assert.False(parameters.RawQueryData.ContainsKey("date_type")); + Assert.Null(parameters.DueDate); + Assert.False(parameters.RawQueryData.ContainsKey("due_date")); + Assert.Null(parameters.DueDateWindow); + Assert.False(parameters.RawQueryData.ContainsKey("due_date_window")); + Assert.Null(parameters.DueDateGt); + Assert.False(parameters.RawQueryData.ContainsKey("due_date[gt]")); + Assert.Null(parameters.DueDateLt); + Assert.False(parameters.RawQueryData.ContainsKey("due_date[lt]")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("external_customer_id")); + Assert.Null(parameters.InvoiceDateGt); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[gt]")); + Assert.Null(parameters.InvoiceDateGte); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[gte]")); + Assert.Null(parameters.InvoiceDateLt); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[lt]")); + Assert.Null(parameters.InvoiceDateLte); + Assert.False(parameters.RawQueryData.ContainsKey("invoice_date[lte]")); + Assert.Null(parameters.IsRecurring); + Assert.False(parameters.RawQueryData.ContainsKey("is_recurring")); + Assert.Null(parameters.Status); + Assert.False(parameters.RawQueryData.ContainsKey("status")); + Assert.Null(parameters.SubscriptionID); + Assert.False(parameters.RawQueryData.ContainsKey("subscription_id")); + } +} + +public class DateTypeTest : TestBase +{ + [Theory] + [InlineData(DateType.DueDate)] + [InlineData(DateType.InvoiceDate)] + public void Validation_Works(DateType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DateType.DueDate)] + [InlineData(DateType.InvoiceDate)] + public void SerializationRoundtrip_Works(DateType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Draft)] + [InlineData(Status.Issued)] + [InlineData(Status.Paid)] + [InlineData(Status.Synced)] + [InlineData(Status.Void)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Draft)] + [InlineData(Status.Issued)] + [InlineData(Status.Paid)] + [InlineData(Status.Synced)] + [InlineData(Status.Void)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceMarkPaidParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceMarkPaidParamsTest.cs new file mode 100644 index 00000000..1900d615 --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceMarkPaidParamsTest.cs @@ -0,0 +1,61 @@ +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceMarkPaidParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceMarkPaidParams + { + InvoiceID = "invoice_id", + PaymentReceivedDate = "2023-09-22", + ExternalID = "external_payment_id_123", + Notes = "notes", + }; + + string expectedInvoiceID = "invoice_id"; + string expectedPaymentReceivedDate = "2023-09-22"; + string expectedExternalID = "external_payment_id_123"; + string expectedNotes = "notes"; + + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + Assert.Equal(expectedPaymentReceivedDate, parameters.PaymentReceivedDate); + Assert.Equal(expectedExternalID, parameters.ExternalID); + Assert.Equal(expectedNotes, parameters.Notes); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceMarkPaidParams + { + InvoiceID = "invoice_id", + PaymentReceivedDate = "2023-09-22", + }; + + Assert.Null(parameters.ExternalID); + Assert.False(parameters.RawBodyData.ContainsKey("external_id")); + Assert.Null(parameters.Notes); + Assert.False(parameters.RawBodyData.ContainsKey("notes")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new InvoiceMarkPaidParams + { + InvoiceID = "invoice_id", + PaymentReceivedDate = "2023-09-22", + + ExternalID = null, + Notes = null, + }; + + Assert.Null(parameters.ExternalID); + Assert.False(parameters.RawBodyData.ContainsKey("external_id")); + Assert.Null(parameters.Notes); + Assert.False(parameters.RawBodyData.ContainsKey("notes")); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoicePayParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoicePayParamsTest.cs new file mode 100644 index 00000000..6a2175c3 --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoicePayParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoicePayParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoicePayParams { InvoiceID = "invoice_id" }; + + string expectedInvoiceID = "invoice_id"; + + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceUpdateParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceUpdateParamsTest.cs new file mode 100644 index 00000000..a06a9caa --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceUpdateParamsTest.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceUpdateParams + { + InvoiceID = "invoice_id", + DueDate = "2023-09-22", + InvoiceDate = "2023-09-22", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + }; + + string expectedInvoiceID = "invoice_id"; + InvoiceUpdateParamsDueDate expectedDueDate = "2023-09-22"; + InvoiceDate expectedInvoiceDate = "2023-09-22"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + long expectedNetTerms = 0; + + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + Assert.Equal(expectedDueDate, parameters.DueDate); + Assert.Equal(expectedInvoiceDate, parameters.InvoiceDate); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedNetTerms, parameters.NetTerms); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new InvoiceUpdateParams { InvoiceID = "invoice_id" }; + + Assert.Null(parameters.DueDate); + Assert.False(parameters.RawBodyData.ContainsKey("due_date")); + Assert.Null(parameters.InvoiceDate); + Assert.False(parameters.RawBodyData.ContainsKey("invoice_date")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new InvoiceUpdateParams + { + InvoiceID = "invoice_id", + + DueDate = null, + InvoiceDate = null, + Metadata = null, + NetTerms = null, + }; + + Assert.Null(parameters.DueDate); + Assert.False(parameters.RawBodyData.ContainsKey("due_date")); + Assert.Null(parameters.InvoiceDate); + Assert.False(parameters.RawBodyData.ContainsKey("invoice_date")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + } +} + +public class InvoiceUpdateParamsDueDateTest : TestBase +{ + [Fact] + public void DateValidationWorks() + { + InvoiceUpdateParamsDueDate value = new("2019-12-27"); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + InvoiceUpdateParamsDueDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + InvoiceUpdateParamsDueDate value = new("2019-12-27"); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + InvoiceUpdateParamsDueDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class InvoiceDateTest : TestBase +{ + [Fact] + public void DateValidationWorks() + { + InvoiceDate value = new("2019-12-27"); + value.Validate(); + } + + [Fact] + public void DateTimeValidationWorks() + { + InvoiceDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void DateSerializationRoundtripWorks() + { + InvoiceDate value = new("2019-12-27"); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + InvoiceDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Invoices/InvoiceVoidParamsTest.cs b/src/Orb.Tests/Models/Invoices/InvoiceVoidParamsTest.cs new file mode 100644 index 00000000..41e1616a --- /dev/null +++ b/src/Orb.Tests/Models/Invoices/InvoiceVoidParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Invoices; + +namespace Orb.Tests.Models.Invoices; + +public class InvoiceVoidParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new InvoiceVoidParams { InvoiceID = "invoice_id" }; + + string expectedInvoiceID = "invoice_id"; + + Assert.Equal(expectedInvoiceID, parameters.InvoiceID); + } +} diff --git a/src/Orb.Tests/Models/ItemSlimTest.cs b/src/Orb.Tests/Models/ItemSlimTest.cs new file mode 100644 index 00000000..c5a54b75 --- /dev/null +++ b/src/Orb.Tests/Models/ItemSlimTest.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class ItemSlimTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ItemSlim { ID = "id", Name = "name" }; + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ItemSlim { ID = "id", Name = "name" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ItemSlim { ID = "id", Name = "name" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new ItemSlim { ID = "id", Name = "name" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemArchiveParamsTest.cs b/src/Orb.Tests/Models/Items/ItemArchiveParamsTest.cs new file mode 100644 index 00000000..8cb4eb2c --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemArchiveParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemArchiveParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ItemArchiveParams { ItemID = "item_id" }; + + string expectedItemID = "item_id"; + + Assert.Equal(expectedItemID, parameters.ItemID); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemCreateParamsTest.cs b/src/Orb.Tests/Models/Items/ItemCreateParamsTest.cs new file mode 100644 index 00000000..bd2782b0 --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemCreateParamsTest.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ItemCreateParams + { + Name = "API requests", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedName = "API requests"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedName, parameters.Name); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ItemCreateParams { Name = "API requests" }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ItemCreateParams + { + Name = "API requests", + + Metadata = null, + }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemFetchParamsTest.cs b/src/Orb.Tests/Models/Items/ItemFetchParamsTest.cs new file mode 100644 index 00000000..371be531 --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ItemFetchParams { ItemID = "item_id" }; + + string expectedItemID = "item_id"; + + Assert.Equal(expectedItemID, parameters.ItemID); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemListPageResponseTest.cs b/src/Orb.Tests/Models/Items/ItemListPageResponseTest.cs new file mode 100644 index 00000000..0c35dad8 --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemListPageResponseTest.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ItemListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ItemListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ItemListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new ItemListPageResponse + { + Data = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemListParamsTest.cs b/src/Orb.Tests/Models/Items/ItemListParamsTest.cs new file mode 100644 index 00000000..c3cd07c6 --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemListParamsTest.cs @@ -0,0 +1,65 @@ +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ItemListParams { Cursor = "cursor", Limit = 1 }; + + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ItemListParams { Cursor = "cursor" }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new ItemListParams + { + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ItemListParams { Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ItemListParams + { + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemTest.cs b/src/Orb.Tests/Models/Items/ItemTest.cs new file mode 100644 index 00000000..83011c8b --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemTest.cs @@ -0,0 +1,406 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedID = "id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + DateTimeOffset expectedArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedExternalConnections.Count, model.ExternalConnections.Count); + for (int i = 0; i < expectedExternalConnections.Count; i++) + { + Assert.Equal(expectedExternalConnections[i], model.ExternalConnections[i]); + } + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedArchivedAt, model.ArchivedAt); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + DateTimeOffset expectedArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedExternalConnections.Count, deserialized.ExternalConnections.Count); + for (int i = 0; i < expectedExternalConnections.Count; i++) + { + Assert.Equal(expectedExternalConnections[i], deserialized.ExternalConnections[i]); + } + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedArchivedAt, deserialized.ArchivedAt); + } + + [Fact] + public void Validation_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + Assert.Null(model.ArchivedAt); + Assert.False(model.RawData.ContainsKey("archived_at")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + + ArchivedAt = null, + }; + + Assert.Null(model.ArchivedAt); + Assert.True(model.RawData.ContainsKey("archived_at")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Item + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + + ArchivedAt = null, + }; + + model.Validate(); + } +} + +public class ItemExternalConnectionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ItemExternalConnection + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + ApiEnum< + string, + ItemExternalConnectionExternalConnectionName + > expectedExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe; + string expectedExternalEntityID = "external_entity_id"; + + Assert.Equal(expectedExternalConnectionName, model.ExternalConnectionName); + Assert.Equal(expectedExternalEntityID, model.ExternalEntityID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ItemExternalConnection + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ItemExternalConnection + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum< + string, + ItemExternalConnectionExternalConnectionName + > expectedExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe; + string expectedExternalEntityID = "external_entity_id"; + + Assert.Equal(expectedExternalConnectionName, deserialized.ExternalConnectionName); + Assert.Equal(expectedExternalEntityID, deserialized.ExternalEntityID); + } + + [Fact] + public void Validation_Works() + { + var model = new ItemExternalConnection + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + model.Validate(); + } +} + +public class ItemExternalConnectionExternalConnectionNameTest : TestBase +{ + [Theory] + [InlineData(ItemExternalConnectionExternalConnectionName.Stripe)] + [InlineData(ItemExternalConnectionExternalConnectionName.Quickbooks)] + [InlineData(ItemExternalConnectionExternalConnectionName.BillCom)] + [InlineData(ItemExternalConnectionExternalConnectionName.Netsuite)] + [InlineData(ItemExternalConnectionExternalConnectionName.Taxjar)] + [InlineData(ItemExternalConnectionExternalConnectionName.Avalara)] + [InlineData(ItemExternalConnectionExternalConnectionName.Anrok)] + [InlineData(ItemExternalConnectionExternalConnectionName.Numeral)] + public void Validation_Works(ItemExternalConnectionExternalConnectionName rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ItemExternalConnectionExternalConnectionName.Stripe)] + [InlineData(ItemExternalConnectionExternalConnectionName.Quickbooks)] + [InlineData(ItemExternalConnectionExternalConnectionName.BillCom)] + [InlineData(ItemExternalConnectionExternalConnectionName.Netsuite)] + [InlineData(ItemExternalConnectionExternalConnectionName.Taxjar)] + [InlineData(ItemExternalConnectionExternalConnectionName.Avalara)] + [InlineData(ItemExternalConnectionExternalConnectionName.Anrok)] + [InlineData(ItemExternalConnectionExternalConnectionName.Numeral)] + public void SerializationRoundtrip_Works(ItemExternalConnectionExternalConnectionName rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Items/ItemUpdateParamsTest.cs b/src/Orb.Tests/Models/Items/ItemUpdateParamsTest.cs new file mode 100644 index 00000000..5bc3f45c --- /dev/null +++ b/src/Orb.Tests/Models/Items/ItemUpdateParamsTest.cs @@ -0,0 +1,229 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Items; + +namespace Orb.Tests.Models.Items; + +public class ItemUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ItemUpdateParams + { + ItemID = "item_id", + ExternalConnections = + [ + new() + { + ExternalConnectionName = ExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + }; + + string expectedItemID = "item_id"; + List expectedExternalConnections = + [ + new() + { + ExternalConnectionName = ExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + + Assert.Equal(expectedItemID, parameters.ItemID); + Assert.NotNull(parameters.ExternalConnections); + Assert.Equal(expectedExternalConnections.Count, parameters.ExternalConnections.Count); + for (int i = 0; i < expectedExternalConnections.Count; i++) + { + Assert.Equal(expectedExternalConnections[i], parameters.ExternalConnections[i]); + } + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedName, parameters.Name); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ItemUpdateParams { ItemID = "item_id" }; + + Assert.Null(parameters.ExternalConnections); + Assert.False(parameters.RawBodyData.ContainsKey("external_connections")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ItemUpdateParams + { + ItemID = "item_id", + + ExternalConnections = null, + Metadata = null, + Name = null, + }; + + Assert.Null(parameters.ExternalConnections); + Assert.False(parameters.RawBodyData.ContainsKey("external_connections")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + } +} + +public class ExternalConnectionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ExternalConnection + { + ExternalConnectionName = ExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + ApiEnum expectedExternalConnectionName = + ExternalConnectionName.Stripe; + string expectedExternalEntityID = "external_entity_id"; + + Assert.Equal(expectedExternalConnectionName, model.ExternalConnectionName); + Assert.Equal(expectedExternalEntityID, model.ExternalEntityID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ExternalConnection + { + ExternalConnectionName = ExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ExternalConnection + { + ExternalConnectionName = ExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedExternalConnectionName = + ExternalConnectionName.Stripe; + string expectedExternalEntityID = "external_entity_id"; + + Assert.Equal(expectedExternalConnectionName, deserialized.ExternalConnectionName); + Assert.Equal(expectedExternalEntityID, deserialized.ExternalEntityID); + } + + [Fact] + public void Validation_Works() + { + var model = new ExternalConnection + { + ExternalConnectionName = ExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }; + + model.Validate(); + } +} + +public class ExternalConnectionNameTest : TestBase +{ + [Theory] + [InlineData(ExternalConnectionName.Stripe)] + [InlineData(ExternalConnectionName.Quickbooks)] + [InlineData(ExternalConnectionName.BillCom)] + [InlineData(ExternalConnectionName.Netsuite)] + [InlineData(ExternalConnectionName.Taxjar)] + [InlineData(ExternalConnectionName.Avalara)] + [InlineData(ExternalConnectionName.Anrok)] + [InlineData(ExternalConnectionName.Numeral)] + public void Validation_Works(ExternalConnectionName rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ExternalConnectionName.Stripe)] + [InlineData(ExternalConnectionName.Quickbooks)] + [InlineData(ExternalConnectionName.BillCom)] + [InlineData(ExternalConnectionName.Netsuite)] + [InlineData(ExternalConnectionName.Taxjar)] + [InlineData(ExternalConnectionName.Avalara)] + [InlineData(ExternalConnectionName.Anrok)] + [InlineData(ExternalConnectionName.Numeral)] + public void SerializationRoundtrip_Works(ExternalConnectionName rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MatrixConfigTest.cs b/src/Orb.Tests/Models/MatrixConfigTest.cs new file mode 100644 index 00000000..98768f5a --- /dev/null +++ b/src/Orb.Tests/Models/MatrixConfigTest.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MatrixConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixConfig + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + string expectedDefaultUnitAmount = "default_unit_amount"; + List expectedDimensions = ["string"]; + List expectedMatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedDefaultUnitAmount, model.DefaultUnitAmount); + Assert.Equal(expectedDimensions.Count, model.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], model.Dimensions[i]); + } + Assert.Equal(expectedMatrixValues.Count, model.MatrixValues.Count); + for (int i = 0; i < expectedMatrixValues.Count; i++) + { + Assert.Equal(expectedMatrixValues[i], model.MatrixValues[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixConfig + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixConfig + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedDefaultUnitAmount = "default_unit_amount"; + List expectedDimensions = ["string"]; + List expectedMatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedDefaultUnitAmount, deserialized.DefaultUnitAmount); + Assert.Equal(expectedDimensions.Count, deserialized.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], deserialized.Dimensions[i]); + } + Assert.Equal(expectedMatrixValues.Count, deserialized.MatrixValues.Count); + for (int i = 0; i < expectedMatrixValues.Count; i++) + { + Assert.Equal(expectedMatrixValues[i], deserialized.MatrixValues[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixConfig + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/MatrixSubLineItemTest.cs b/src/Orb.Tests/Models/MatrixSubLineItemTest.cs new file mode 100644 index 00000000..0583df49 --- /dev/null +++ b/src/Orb.Tests/Models/MatrixSubLineItemTest.cs @@ -0,0 +1,238 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MatrixSubLineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }; + + string expectedAmount = "9.00"; + SubLineItemGrouping expectedGrouping = new() { Key = "region", Value = "west" }; + SubLineItemMatrixConfig expectedMatrixConfig = new(["string"]); + string expectedName = "Tier One"; + double expectedQuantity = 5; + ApiEnum expectedType = MatrixSubLineItemType.Matrix; + double expectedScaledQuantity = 0; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedMatrixConfig, model.MatrixConfig); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedScaledQuantity, model.ScaledQuantity); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "9.00"; + SubLineItemGrouping expectedGrouping = new() { Key = "region", Value = "west" }; + SubLineItemMatrixConfig expectedMatrixConfig = new(["string"]); + string expectedName = "Tier One"; + double expectedQuantity = 5; + ApiEnum expectedType = MatrixSubLineItemType.Matrix; + double expectedScaledQuantity = 0; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedMatrixConfig, deserialized.MatrixConfig); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedScaledQuantity, deserialized.ScaledQuantity); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + }; + + Assert.Null(model.ScaledQuantity); + Assert.False(model.RawData.ContainsKey("scaled_quantity")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + + ScaledQuantity = null, + }; + + Assert.Null(model.ScaledQuantity); + Assert.True(model.RawData.ContainsKey("scaled_quantity")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MatrixSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = MatrixSubLineItemType.Matrix, + + ScaledQuantity = null, + }; + + model.Validate(); + } +} + +public class MatrixSubLineItemTypeTest : TestBase +{ + [Theory] + [InlineData(MatrixSubLineItemType.Matrix)] + public void Validation_Works(MatrixSubLineItemType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixSubLineItemType.Matrix)] + public void SerializationRoundtrip_Works(MatrixSubLineItemType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MatrixValueTest.cs b/src/Orb.Tests/Models/MatrixValueTest.cs new file mode 100644 index 00000000..64f5b0bb --- /dev/null +++ b/src/Orb.Tests/Models/MatrixValueTest.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MatrixValueTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixValue { DimensionValues = ["string"], UnitAmount = "unit_amount" }; + + List expectedDimensionValues = ["string"]; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixValue { DimensionValues = ["string"], UnitAmount = "unit_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixValue { DimensionValues = ["string"], UnitAmount = "unit_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDimensionValues = ["string"]; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixValue { DimensionValues = ["string"], UnitAmount = "unit_amount" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/MatrixWithAllocationConfigTest.cs b/src/Orb.Tests/Models/MatrixWithAllocationConfigTest.cs new file mode 100644 index 00000000..0271af9d --- /dev/null +++ b/src/Orb.Tests/Models/MatrixWithAllocationConfigTest.cs @@ -0,0 +1,185 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MatrixWithAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithAllocationConfig + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + string expectedAllocation = "allocation"; + string expectedDefaultUnitAmount = "default_unit_amount"; + List expectedDimensions = ["string"]; + List expectedMatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedDefaultUnitAmount, model.DefaultUnitAmount); + Assert.Equal(expectedDimensions.Count, model.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], model.Dimensions[i]); + } + Assert.Equal(expectedMatrixValues.Count, model.MatrixValues.Count); + for (int i = 0; i < expectedMatrixValues.Count; i++) + { + Assert.Equal(expectedMatrixValues[i], model.MatrixValues[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithAllocationConfig + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithAllocationConfig + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedDefaultUnitAmount = "default_unit_amount"; + List expectedDimensions = ["string"]; + List expectedMatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedDefaultUnitAmount, deserialized.DefaultUnitAmount); + Assert.Equal(expectedDimensions.Count, deserialized.Dimensions.Count); + for (int i = 0; i < expectedDimensions.Count; i++) + { + Assert.Equal(expectedDimensions[i], deserialized.Dimensions[i]); + } + Assert.Equal(expectedMatrixValues.Count, deserialized.MatrixValues.Count); + for (int i = 0; i < expectedMatrixValues.Count; i++) + { + Assert.Equal(expectedMatrixValues[i], deserialized.MatrixValues[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithAllocationConfig + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class MatrixWithAllocationConfigMatrixValueTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithAllocationConfigMatrixValue + { + DimensionValues = ["string"], + UnitAmount = "unit_amount", + }; + + List expectedDimensionValues = ["string"]; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithAllocationConfigMatrixValue + { + DimensionValues = ["string"], + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithAllocationConfigMatrixValue + { + DimensionValues = ["string"], + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedDimensionValues = ["string"]; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithAllocationConfigMatrixValue + { + DimensionValues = ["string"], + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/MaximumIntervalTest.cs b/src/Orb.Tests/Models/MaximumIntervalTest.cs new file mode 100644 index 00000000..e5da4822 --- /dev/null +++ b/src/Orb.Tests/Models/MaximumIntervalTest.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MaximumIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaximumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + List expectedAppliesToPriceIntervalIDs = ["string"]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMaximumAmount = "maximum_amount"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + model.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIntervalIDs[i], model.AppliesToPriceIntervalIDs[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaximumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaximumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAppliesToPriceIntervalIDs = ["string"]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMaximumAmount = "maximum_amount"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + deserialized.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal( + expectedAppliesToPriceIntervalIDs[i], + deserialized.AppliesToPriceIntervalIDs[i] + ); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new MaximumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class MaximumIntervalFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaximumIntervalFilter + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MaximumIntervalFilterField.PriceID; + ApiEnum expectedOperator = + MaximumIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaximumIntervalFilter + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaximumIntervalFilter + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MaximumIntervalFilterField.PriceID; + ApiEnum expectedOperator = + MaximumIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MaximumIntervalFilter + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MaximumIntervalFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MaximumIntervalFilterField.PriceID)] + [InlineData(MaximumIntervalFilterField.ItemID)] + [InlineData(MaximumIntervalFilterField.PriceType)] + [InlineData(MaximumIntervalFilterField.Currency)] + [InlineData(MaximumIntervalFilterField.PricingUnitID)] + public void Validation_Works(MaximumIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaximumIntervalFilterField.PriceID)] + [InlineData(MaximumIntervalFilterField.ItemID)] + [InlineData(MaximumIntervalFilterField.PriceType)] + [InlineData(MaximumIntervalFilterField.Currency)] + [InlineData(MaximumIntervalFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MaximumIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MaximumIntervalFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MaximumIntervalFilterOperator.Includes)] + [InlineData(MaximumIntervalFilterOperator.Excludes)] + public void Validation_Works(MaximumIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaximumIntervalFilterOperator.Includes)] + [InlineData(MaximumIntervalFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MaximumIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MaximumTest.cs b/src/Orb.Tests/Models/MaximumTest.cs new file mode 100644 index 00000000..d012f24d --- /dev/null +++ b/src/Orb.Tests/Models/MaximumTest.cs @@ -0,0 +1,349 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MaximumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Maximum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMaximumAmount = "maximum_amount"; + + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Maximum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Maximum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMaximumAmount = "maximum_amount"; + + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Maximum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + + model.Validate(); + } +} + +public class MaximumFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaximumFilter + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = MaximumFilterField.PriceID; + ApiEnum expectedOperator = MaximumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaximumFilter + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaximumFilter + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = MaximumFilterField.PriceID; + ApiEnum expectedOperator = MaximumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MaximumFilter + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MaximumFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MaximumFilterField.PriceID)] + [InlineData(MaximumFilterField.ItemID)] + [InlineData(MaximumFilterField.PriceType)] + [InlineData(MaximumFilterField.Currency)] + [InlineData(MaximumFilterField.PricingUnitID)] + public void Validation_Works(MaximumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaximumFilterField.PriceID)] + [InlineData(MaximumFilterField.ItemID)] + [InlineData(MaximumFilterField.PriceType)] + [InlineData(MaximumFilterField.Currency)] + [InlineData(MaximumFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MaximumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MaximumFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MaximumFilterOperator.Includes)] + [InlineData(MaximumFilterOperator.Excludes)] + public void Validation_Works(MaximumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaximumFilterOperator.Includes)] + [InlineData(MaximumFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MaximumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Metrics/BillableMetricTest.cs b/src/Orb.Tests/Models/Metrics/BillableMetricTest.cs new file mode 100644 index 00000000..6ddaa6bd --- /dev/null +++ b/src/Orb.Tests/Models/Metrics/BillableMetricTest.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Items; +using Orb.Models.Metrics; + +namespace Orb.Tests.Models.Metrics; + +public class BillableMetricTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BillableMetric + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }; + + string expectedID = "id"; + string expectedDescription = "description"; + Item expectedItem = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + ApiEnum expectedStatus = Status.Active; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedStatus, model.Status); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BillableMetric + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BillableMetric + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedDescription = "description"; + Item expectedItem = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + ApiEnum expectedStatus = Status.Active; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedStatus, deserialized.Status); + } + + [Fact] + public void Validation_Works() + { + var model = new BillableMetric + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }; + + model.Validate(); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Draft)] + [InlineData(Status.Archived)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Draft)] + [InlineData(Status.Archived)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Metrics/MetricCreateParamsTest.cs b/src/Orb.Tests/Models/Metrics/MetricCreateParamsTest.cs new file mode 100644 index 00000000..4b2c10b0 --- /dev/null +++ b/src/Orb.Tests/Models/Metrics/MetricCreateParamsTest.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using Orb.Models.Metrics; + +namespace Orb.Tests.Models.Metrics; + +public class MetricCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new MetricCreateParams + { + Description = "Sum of bytes downloaded in fast mode", + ItemID = "item_id", + Name = "Bytes downloaded", + Sql = "SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedDescription = "Sum of bytes downloaded in fast mode"; + string expectedItemID = "item_id"; + string expectedName = "Bytes downloaded"; + string expectedSql = + "SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedDescription, parameters.Description); + Assert.Equal(expectedItemID, parameters.ItemID); + Assert.Equal(expectedName, parameters.Name); + Assert.Equal(expectedSql, parameters.Sql); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new MetricCreateParams + { + Description = "Sum of bytes downloaded in fast mode", + ItemID = "item_id", + Name = "Bytes downloaded", + Sql = "SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", + }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new MetricCreateParams + { + Description = "Sum of bytes downloaded in fast mode", + ItemID = "item_id", + Name = "Bytes downloaded", + Sql = "SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", + + Metadata = null, + }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/Metrics/MetricFetchParamsTest.cs b/src/Orb.Tests/Models/Metrics/MetricFetchParamsTest.cs new file mode 100644 index 00000000..29511f39 --- /dev/null +++ b/src/Orb.Tests/Models/Metrics/MetricFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Metrics; + +namespace Orb.Tests.Models.Metrics; + +public class MetricFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new MetricFetchParams { MetricID = "metric_id" }; + + string expectedMetricID = "metric_id"; + + Assert.Equal(expectedMetricID, parameters.MetricID); + } +} diff --git a/src/Orb.Tests/Models/Metrics/MetricListPageResponseTest.cs b/src/Orb.Tests/Models/Metrics/MetricListPageResponseTest.cs new file mode 100644 index 00000000..6c5e84ae --- /dev/null +++ b/src/Orb.Tests/Models/Metrics/MetricListPageResponseTest.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Items; +using Orb.Models.Metrics; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Metrics; + +public class MetricListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MetricListPageResponse + { + Data = + [ + new() + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MetricListPageResponse + { + Data = + [ + new() + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MetricListPageResponse + { + Data = + [ + new() + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new MetricListPageResponse + { + Data = + [ + new() + { + ID = "id", + Description = "description", + Item = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalConnections = + [ + new() + { + ExternalConnectionName = + ItemExternalConnectionExternalConnectionName.Stripe, + ExternalEntityID = "external_entity_id", + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + ArchivedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + Status = Status.Active, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Metrics/MetricListParamsTest.cs b/src/Orb.Tests/Models/Metrics/MetricListParamsTest.cs new file mode 100644 index 00000000..146b7f3a --- /dev/null +++ b/src/Orb.Tests/Models/Metrics/MetricListParamsTest.cs @@ -0,0 +1,113 @@ +using System; +using Orb.Models.Metrics; + +namespace Orb.Tests.Models.Metrics; + +public class MetricListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new MetricListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + Limit = 1, + }; + + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new MetricListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new MetricListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new MetricListParams { Limit = 1 }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new MetricListParams + { + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Cursor = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Metrics/MetricUpdateParamsTest.cs b/src/Orb.Tests/Models/Metrics/MetricUpdateParamsTest.cs new file mode 100644 index 00000000..5950f609 --- /dev/null +++ b/src/Orb.Tests/Models/Metrics/MetricUpdateParamsTest.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using Orb.Models.Metrics; + +namespace Orb.Tests.Models.Metrics; + +public class MetricUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new MetricUpdateParams + { + MetricID = "metric_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedMetricID = "metric_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedMetricID, parameters.MetricID); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new MetricUpdateParams { MetricID = "metric_id" }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new MetricUpdateParams + { + MetricID = "metric_id", + + Metadata = null, + }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/MinimumIntervalTest.cs b/src/Orb.Tests/Models/MinimumIntervalTest.cs new file mode 100644 index 00000000..120e33d5 --- /dev/null +++ b/src/Orb.Tests/Models/MinimumIntervalTest.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MinimumIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MinimumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + List expectedAppliesToPriceIntervalIDs = ["string"]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + model.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIntervalIDs[i], model.AppliesToPriceIntervalIDs[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MinimumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MinimumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAppliesToPriceIntervalIDs = ["string"]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMinimumAmount = "minimum_amount"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + deserialized.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal( + expectedAppliesToPriceIntervalIDs[i], + deserialized.AppliesToPriceIntervalIDs[i] + ); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new MinimumInterval + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class MinimumIntervalFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MinimumIntervalFilter + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MinimumIntervalFilterField.PriceID; + ApiEnum expectedOperator = + MinimumIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MinimumIntervalFilter + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MinimumIntervalFilter + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MinimumIntervalFilterField.PriceID; + ApiEnum expectedOperator = + MinimumIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MinimumIntervalFilter + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MinimumIntervalFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MinimumIntervalFilterField.PriceID)] + [InlineData(MinimumIntervalFilterField.ItemID)] + [InlineData(MinimumIntervalFilterField.PriceType)] + [InlineData(MinimumIntervalFilterField.Currency)] + [InlineData(MinimumIntervalFilterField.PricingUnitID)] + public void Validation_Works(MinimumIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MinimumIntervalFilterField.PriceID)] + [InlineData(MinimumIntervalFilterField.ItemID)] + [InlineData(MinimumIntervalFilterField.PriceType)] + [InlineData(MinimumIntervalFilterField.Currency)] + [InlineData(MinimumIntervalFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MinimumIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MinimumIntervalFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MinimumIntervalFilterOperator.Includes)] + [InlineData(MinimumIntervalFilterOperator.Excludes)] + public void Validation_Works(MinimumIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MinimumIntervalFilterOperator.Includes)] + [InlineData(MinimumIntervalFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MinimumIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MinimumTest.cs b/src/Orb.Tests/Models/MinimumTest.cs new file mode 100644 index 00000000..a6d65cce --- /dev/null +++ b/src/Orb.Tests/Models/MinimumTest.cs @@ -0,0 +1,349 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Minimum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMinimumAmount = "minimum_amount"; + + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Minimum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Minimum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedMinimumAmount = "minimum_amount"; + + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Minimum + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + + model.Validate(); + } +} + +public class MinimumFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MinimumFilter + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = MinimumFilterField.PriceID; + ApiEnum expectedOperator = MinimumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MinimumFilter + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MinimumFilter + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = MinimumFilterField.PriceID; + ApiEnum expectedOperator = MinimumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MinimumFilter + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MinimumFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MinimumFilterField.PriceID)] + [InlineData(MinimumFilterField.ItemID)] + [InlineData(MinimumFilterField.PriceType)] + [InlineData(MinimumFilterField.Currency)] + [InlineData(MinimumFilterField.PricingUnitID)] + public void Validation_Works(MinimumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MinimumFilterField.PriceID)] + [InlineData(MinimumFilterField.ItemID)] + [InlineData(MinimumFilterField.PriceType)] + [InlineData(MinimumFilterField.Currency)] + [InlineData(MinimumFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MinimumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MinimumFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MinimumFilterOperator.Includes)] + [InlineData(MinimumFilterOperator.Excludes)] + public void Validation_Works(MinimumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MinimumFilterOperator.Includes)] + [InlineData(MinimumFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MinimumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MonetaryAmountDiscountAdjustmentTest.cs b/src/Orb.Tests/Models/MonetaryAmountDiscountAdjustmentTest.cs new file mode 100644 index 00000000..1f831367 --- /dev/null +++ b/src/Orb.Tests/Models/MonetaryAmountDiscountAdjustmentTest.cs @@ -0,0 +1,465 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MonetaryAmountDiscountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = AdjustmentType.AmountDiscount; + string expectedAmount = "amount"; + string expectedAmountDiscount = "amount_discount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = AdjustmentType.AmountDiscount; + string expectedAmount = "amount"; + string expectedAmountDiscount = "amount_discount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = AdjustmentType.AmountDiscount, + Amount = "amount", + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class AdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(AdjustmentType.AmountDiscount)] + public void Validation_Works(AdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AdjustmentType.AmountDiscount)] + public void SerializationRoundtrip_Works(AdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryAmountDiscountAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryAmountDiscountAdjustmentFilter + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MonetaryAmountDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryAmountDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryAmountDiscountAdjustmentFilter + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryAmountDiscountAdjustmentFilter + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MonetaryAmountDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryAmountDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryAmountDiscountAdjustmentFilter + { + Field = MonetaryAmountDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MonetaryAmountDiscountAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.PriceID)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.ItemID)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.PriceType)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.Currency)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(MonetaryAmountDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.PriceID)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.ItemID)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.PriceType)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.Currency)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MonetaryAmountDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryAmountDiscountAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MonetaryAmountDiscountAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterOperator.Excludes)] + public void Validation_Works(MonetaryAmountDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryAmountDiscountAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryAmountDiscountAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + MonetaryAmountDiscountAdjustmentFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MonetaryMaximumAdjustmentTest.cs b/src/Orb.Tests/Models/MonetaryMaximumAdjustmentTest.cs new file mode 100644 index 00000000..b7d41d3b --- /dev/null +++ b/src/Orb.Tests/Models/MonetaryMaximumAdjustmentTest.cs @@ -0,0 +1,465 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MonetaryMaximumAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryMaximumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryMaximumAdjustmentAdjustmentType.Maximum; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedMaximumAmount = "maximum_amount"; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryMaximumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryMaximumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryMaximumAdjustmentAdjustmentType.Maximum; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedMaximumAmount = "maximum_amount"; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryMaximumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMaximumAdjustmentAdjustmentType.Maximum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class MonetaryMaximumAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(MonetaryMaximumAdjustmentAdjustmentType.Maximum)] + public void Validation_Works(MonetaryMaximumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryMaximumAdjustmentAdjustmentType.Maximum)] + public void SerializationRoundtrip_Works(MonetaryMaximumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryMaximumAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryMaximumAdjustmentFilter + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MonetaryMaximumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryMaximumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryMaximumAdjustmentFilter + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryMaximumAdjustmentFilter + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MonetaryMaximumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryMaximumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryMaximumAdjustmentFilter + { + Field = MonetaryMaximumAdjustmentFilterField.PriceID, + Operator = MonetaryMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MonetaryMaximumAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MonetaryMaximumAdjustmentFilterField.PriceID)] + [InlineData(MonetaryMaximumAdjustmentFilterField.ItemID)] + [InlineData(MonetaryMaximumAdjustmentFilterField.PriceType)] + [InlineData(MonetaryMaximumAdjustmentFilterField.Currency)] + [InlineData(MonetaryMaximumAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(MonetaryMaximumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryMaximumAdjustmentFilterField.PriceID)] + [InlineData(MonetaryMaximumAdjustmentFilterField.ItemID)] + [InlineData(MonetaryMaximumAdjustmentFilterField.PriceType)] + [InlineData(MonetaryMaximumAdjustmentFilterField.Currency)] + [InlineData(MonetaryMaximumAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MonetaryMaximumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryMaximumAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MonetaryMaximumAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryMaximumAdjustmentFilterOperator.Excludes)] + public void Validation_Works(MonetaryMaximumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryMaximumAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryMaximumAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MonetaryMaximumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MonetaryMinimumAdjustmentTest.cs b/src/Orb.Tests/Models/MonetaryMinimumAdjustmentTest.cs new file mode 100644 index 00000000..b9b85717 --- /dev/null +++ b/src/Orb.Tests/Models/MonetaryMinimumAdjustmentTest.cs @@ -0,0 +1,473 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MonetaryMinimumAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryMinimumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryMinimumAdjustmentAdjustmentType.Minimum; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedItemID = "item_id"; + string expectedMinimumAmount = "minimum_amount"; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryMinimumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryMinimumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryMinimumAdjustmentAdjustmentType.Minimum; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedItemID = "item_id"; + string expectedMinimumAmount = "minimum_amount"; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryMinimumAdjustment + { + ID = "id", + AdjustmentType = MonetaryMinimumAdjustmentAdjustmentType.Minimum, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class MonetaryMinimumAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(MonetaryMinimumAdjustmentAdjustmentType.Minimum)] + public void Validation_Works(MonetaryMinimumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryMinimumAdjustmentAdjustmentType.Minimum)] + public void SerializationRoundtrip_Works(MonetaryMinimumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryMinimumAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryMinimumAdjustmentFilter + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MonetaryMinimumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryMinimumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryMinimumAdjustmentFilter + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryMinimumAdjustmentFilter + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MonetaryMinimumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryMinimumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryMinimumAdjustmentFilter + { + Field = MonetaryMinimumAdjustmentFilterField.PriceID, + Operator = MonetaryMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MonetaryMinimumAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MonetaryMinimumAdjustmentFilterField.PriceID)] + [InlineData(MonetaryMinimumAdjustmentFilterField.ItemID)] + [InlineData(MonetaryMinimumAdjustmentFilterField.PriceType)] + [InlineData(MonetaryMinimumAdjustmentFilterField.Currency)] + [InlineData(MonetaryMinimumAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(MonetaryMinimumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryMinimumAdjustmentFilterField.PriceID)] + [InlineData(MonetaryMinimumAdjustmentFilterField.ItemID)] + [InlineData(MonetaryMinimumAdjustmentFilterField.PriceType)] + [InlineData(MonetaryMinimumAdjustmentFilterField.Currency)] + [InlineData(MonetaryMinimumAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MonetaryMinimumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryMinimumAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MonetaryMinimumAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryMinimumAdjustmentFilterOperator.Excludes)] + public void Validation_Works(MonetaryMinimumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryMinimumAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryMinimumAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MonetaryMinimumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MonetaryPercentageDiscountAdjustmentTest.cs b/src/Orb.Tests/Models/MonetaryPercentageDiscountAdjustmentTest.cs new file mode 100644 index 00000000..b84e4b16 --- /dev/null +++ b/src/Orb.Tests/Models/MonetaryPercentageDiscountAdjustmentTest.cs @@ -0,0 +1,477 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MonetaryPercentageDiscountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryPercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + double expectedPercentageDiscount = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryPercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryPercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + double expectedPercentageDiscount = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryPercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class MonetaryPercentageDiscountAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount)] + public void Validation_Works(MonetaryPercentageDiscountAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount)] + public void SerializationRoundtrip_Works( + MonetaryPercentageDiscountAdjustmentAdjustmentType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryPercentageDiscountAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryPercentageDiscountAdjustmentFilter + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MonetaryPercentageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryPercentageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryPercentageDiscountAdjustmentFilter + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryPercentageDiscountAdjustmentFilter + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MonetaryPercentageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryPercentageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryPercentageDiscountAdjustmentFilter + { + Field = MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MonetaryPercentageDiscountAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.PriceID)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.ItemID)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.PriceType)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.Currency)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(MonetaryPercentageDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.PriceID)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.ItemID)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.PriceType)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.Currency)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + MonetaryPercentageDiscountAdjustmentFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryPercentageDiscountAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterOperator.Excludes)] + public void Validation_Works(MonetaryPercentageDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryPercentageDiscountAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + MonetaryPercentageDiscountAdjustmentFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/MonetaryUsageDiscountAdjustmentTest.cs b/src/Orb.Tests/Models/MonetaryUsageDiscountAdjustmentTest.cs new file mode 100644 index 00000000..7dc1be0c --- /dev/null +++ b/src/Orb.Tests/Models/MonetaryUsageDiscountAdjustmentTest.cs @@ -0,0 +1,467 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class MonetaryUsageDiscountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + double expectedUsageDiscount = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + Assert.Equal(expectedUsageDiscount, model.UsageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount; + string expectedAmount = "amount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + double expectedUsageDiscount = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + Assert.Equal(expectedUsageDiscount, deserialized.UsageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + model.Validate(); + } +} + +public class MonetaryUsageDiscountAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount)] + public void Validation_Works(MonetaryUsageDiscountAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount)] + public void SerializationRoundtrip_Works(MonetaryUsageDiscountAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryUsageDiscountAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MonetaryUsageDiscountAdjustmentFilter + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MonetaryUsageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MonetaryUsageDiscountAdjustmentFilter + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MonetaryUsageDiscountAdjustmentFilter + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MonetaryUsageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + MonetaryUsageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MonetaryUsageDiscountAdjustmentFilter + { + Field = MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MonetaryUsageDiscountAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.PriceID)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.ItemID)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.PriceType)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.Currency)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(MonetaryUsageDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.PriceID)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.ItemID)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.PriceType)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.Currency)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MonetaryUsageDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MonetaryUsageDiscountAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MonetaryUsageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterOperator.Excludes)] + public void Validation_Works(MonetaryUsageDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MonetaryUsageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(MonetaryUsageDiscountAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MonetaryUsageDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewAllocationPriceTest.cs b/src/Orb.Tests/Models/NewAllocationPriceTest.cs new file mode 100644 index 00000000..acf7c51c --- /dev/null +++ b/src/Orb.Tests/Models/NewAllocationPriceTest.cs @@ -0,0 +1,667 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string expectedAmount = "10.00"; + ApiEnum expectedCadence = Cadence.Monthly; + string expectedCurrency = "USD"; + CustomExpiration expectedCustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + bool expectedExpiresAtEndOfCadence = true; + List expectedFilters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedItemID = "item_id"; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedCustomExpiration, model.CustomExpiration); + Assert.Equal(expectedExpiresAtEndOfCadence, model.ExpiresAtEndOfCadence); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedPerUnitCostBasis, model.PerUnitCostBasis); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "10.00"; + ApiEnum expectedCadence = Cadence.Monthly; + string expectedCurrency = "USD"; + CustomExpiration expectedCustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }; + bool expectedExpiresAtEndOfCadence = true; + List expectedFilters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedItemID = "item_id"; + string expectedPerUnitCostBasis = "per_unit_cost_basis"; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedCustomExpiration, deserialized.CustomExpiration); + Assert.Equal(expectedExpiresAtEndOfCadence, deserialized.ExpiresAtEndOfCadence); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedPerUnitCostBasis, deserialized.PerUnitCostBasis); + } + + [Fact] + public void Validation_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + }; + + Assert.Null(model.PerUnitCostBasis); + Assert.False(model.RawData.ContainsKey("per_unit_cost_basis")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + + // Null should be interpreted as omitted for these properties + PerUnitCostBasis = null, + }; + + Assert.Null(model.PerUnitCostBasis); + Assert.False(model.RawData.ContainsKey("per_unit_cost_basis")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + + // Null should be interpreted as omitted for these properties + PerUnitCostBasis = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + PerUnitCostBasis = "per_unit_cost_basis", + }; + + Assert.Null(model.CustomExpiration); + Assert.False(model.RawData.ContainsKey("custom_expiration")); + Assert.Null(model.ExpiresAtEndOfCadence); + Assert.False(model.RawData.ContainsKey("expires_at_end_of_cadence")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.ItemID); + Assert.False(model.RawData.ContainsKey("item_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + PerUnitCostBasis = "per_unit_cost_basis", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + PerUnitCostBasis = "per_unit_cost_basis", + + CustomExpiration = null, + ExpiresAtEndOfCadence = null, + Filters = null, + ItemID = null, + }; + + Assert.Null(model.CustomExpiration); + Assert.True(model.RawData.ContainsKey("custom_expiration")); + Assert.Null(model.ExpiresAtEndOfCadence); + Assert.True(model.RawData.ContainsKey("expires_at_end_of_cadence")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.ItemID); + Assert.True(model.RawData.ContainsKey("item_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewAllocationPrice + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + PerUnitCostBasis = "per_unit_cost_basis", + + CustomExpiration = null, + ExpiresAtEndOfCadence = null, + Filters = null, + ItemID = null, + }; + + model.Validate(); + } +} + +public class CadenceTest : TestBase +{ + [Theory] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Annual)] + public void Validation_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Annual)] + public void SerializationRoundtrip_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewAllocationPriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewAllocationPriceFilter + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + NewAllocationPriceFilterField.ItemID; + ApiEnum expectedOperator = + NewAllocationPriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewAllocationPriceFilter + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewAllocationPriceFilter + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + NewAllocationPriceFilterField.ItemID; + ApiEnum expectedOperator = + NewAllocationPriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewAllocationPriceFilter + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class NewAllocationPriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(NewAllocationPriceFilterField.ItemID)] + public void Validation_Works(NewAllocationPriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewAllocationPriceFilterField.ItemID)] + public void SerializationRoundtrip_Works(NewAllocationPriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewAllocationPriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(NewAllocationPriceFilterOperator.Includes)] + [InlineData(NewAllocationPriceFilterOperator.Excludes)] + public void Validation_Works(NewAllocationPriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewAllocationPriceFilterOperator.Includes)] + [InlineData(NewAllocationPriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(NewAllocationPriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewAmountDiscountTest.cs b/src/Orb.Tests/Models/NewAmountDiscountTest.cs new file mode 100644 index 00000000..63db3cfd --- /dev/null +++ b/src/Orb.Tests/Models/NewAmountDiscountTest.cs @@ -0,0 +1,787 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewAmountDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + }; + + ApiEnum expectedAdjustmentType = + NewAmountDiscountAdjustmentType.AmountDiscount; + string expectedAmountDiscount = "amount_discount"; + ApiEnum expectedAppliesToAll = AppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = PriceType.Usage; + + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.Equal(expectedAppliesToAll, model.AppliesToAll); + Assert.NotNull(model.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, model.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], model.AppliesToItemIDs[i]); + } + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPriceType, model.PriceType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedAdjustmentType = + NewAmountDiscountAdjustmentType.AmountDiscount; + string expectedAmountDiscount = "amount_discount"; + ApiEnum expectedAppliesToAll = AppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = PriceType.Usage; + + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.Equal(expectedAppliesToAll, deserialized.AppliesToAll); + Assert.NotNull(deserialized.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, deserialized.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], deserialized.AppliesToItemIDs[i]); + } + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPriceType, deserialized.PriceType); + } + + [Fact] + public void Validation_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = PriceType.Usage, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = PriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = PriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = PriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + IsInvoiceLevel = true, + }; + + Assert.Null(model.AppliesToAll); + Assert.False(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.False(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.False(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + IsInvoiceLevel = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + Assert.Null(model.AppliesToAll); + Assert.True(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.True(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.True(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewAmountDiscount + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + model.Validate(); + } +} + +public class NewAmountDiscountAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(NewAmountDiscountAdjustmentType.AmountDiscount)] + public void Validation_Works(NewAmountDiscountAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewAmountDiscountAdjustmentType.AmountDiscount)] + public void SerializationRoundtrip_Works(NewAmountDiscountAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class AppliesToAllTest : TestBase +{ + [Theory] + [InlineData(AppliesToAll.True)] + public void Validation_Works(AppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AppliesToAll.True)] + public void SerializationRoundtrip_Works(AppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewAmountDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewAmountDiscountFilter + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + NewAmountDiscountFilterField.PriceID; + ApiEnum expectedOperator = + NewAmountDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewAmountDiscountFilter + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewAmountDiscountFilter + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + NewAmountDiscountFilterField.PriceID; + ApiEnum expectedOperator = + NewAmountDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewAmountDiscountFilter + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class NewAmountDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(NewAmountDiscountFilterField.PriceID)] + [InlineData(NewAmountDiscountFilterField.ItemID)] + [InlineData(NewAmountDiscountFilterField.PriceType)] + [InlineData(NewAmountDiscountFilterField.Currency)] + [InlineData(NewAmountDiscountFilterField.PricingUnitID)] + public void Validation_Works(NewAmountDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewAmountDiscountFilterField.PriceID)] + [InlineData(NewAmountDiscountFilterField.ItemID)] + [InlineData(NewAmountDiscountFilterField.PriceType)] + [InlineData(NewAmountDiscountFilterField.Currency)] + [InlineData(NewAmountDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(NewAmountDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewAmountDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(NewAmountDiscountFilterOperator.Includes)] + [InlineData(NewAmountDiscountFilterOperator.Excludes)] + public void Validation_Works(NewAmountDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewAmountDiscountFilterOperator.Includes)] + [InlineData(NewAmountDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(NewAmountDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceTypeTest : TestBase +{ + [Theory] + [InlineData(PriceType.Usage)] + [InlineData(PriceType.FixedInAdvance)] + [InlineData(PriceType.FixedInArrears)] + [InlineData(PriceType.Fixed)] + [InlineData(PriceType.InArrears)] + public void Validation_Works(PriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceType.Usage)] + [InlineData(PriceType.FixedInAdvance)] + [InlineData(PriceType.FixedInArrears)] + [InlineData(PriceType.Fixed)] + [InlineData(PriceType.InArrears)] + public void SerializationRoundtrip_Works(PriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewBillingCycleConfigurationTest.cs b/src/Orb.Tests/Models/NewBillingCycleConfigurationTest.cs new file mode 100644 index 00000000..69b340c5 --- /dev/null +++ b/src/Orb.Tests/Models/NewBillingCycleConfigurationTest.cs @@ -0,0 +1,134 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewBillingCycleConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewBillingCycleConfiguration + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + + long expectedDuration = 0; + ApiEnum expectedDurationUnit = + NewBillingCycleConfigurationDurationUnit.Day; + + Assert.Equal(expectedDuration, model.Duration); + Assert.Equal(expectedDurationUnit, model.DurationUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewBillingCycleConfiguration + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewBillingCycleConfiguration + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedDuration = 0; + ApiEnum expectedDurationUnit = + NewBillingCycleConfigurationDurationUnit.Day; + + Assert.Equal(expectedDuration, deserialized.Duration); + Assert.Equal(expectedDurationUnit, deserialized.DurationUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new NewBillingCycleConfiguration + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + + model.Validate(); + } +} + +public class NewBillingCycleConfigurationDurationUnitTest : TestBase +{ + [Theory] + [InlineData(NewBillingCycleConfigurationDurationUnit.Day)] + [InlineData(NewBillingCycleConfigurationDurationUnit.Month)] + public void Validation_Works(NewBillingCycleConfigurationDurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewBillingCycleConfigurationDurationUnit.Day)] + [InlineData(NewBillingCycleConfigurationDurationUnit.Month)] + public void SerializationRoundtrip_Works(NewBillingCycleConfigurationDurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewDimensionalPriceConfigurationTest.cs b/src/Orb.Tests/Models/NewDimensionalPriceConfigurationTest.cs new file mode 100644 index 00000000..3fa6e6e6 --- /dev/null +++ b/src/Orb.Tests/Models/NewDimensionalPriceConfigurationTest.cs @@ -0,0 +1,143 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewDimensionalPriceConfigurationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewDimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + + List expectedDimensionValues = ["string"]; + string expectedDimensionalPriceGroupID = "dimensional_price_group_id"; + string expectedExternalDimensionalPriceGroupID = "external_dimensional_price_group_id"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedDimensionalPriceGroupID, model.DimensionalPriceGroupID); + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + model.ExternalDimensionalPriceGroupID + ); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewDimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewDimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDimensionValues = ["string"]; + string expectedDimensionalPriceGroupID = "dimensional_price_group_id"; + string expectedExternalDimensionalPriceGroupID = "external_dimensional_price_group_id"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedDimensionalPriceGroupID, deserialized.DimensionalPriceGroupID); + Assert.Equal( + expectedExternalDimensionalPriceGroupID, + deserialized.ExternalDimensionalPriceGroupID + ); + } + + [Fact] + public void Validation_Works() + { + var model = new NewDimensionalPriceConfiguration + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewDimensionalPriceConfiguration { DimensionValues = ["string"] }; + + Assert.Null(model.DimensionalPriceGroupID); + Assert.False(model.RawData.ContainsKey("dimensional_price_group_id")); + Assert.Null(model.ExternalDimensionalPriceGroupID); + Assert.False(model.RawData.ContainsKey("external_dimensional_price_group_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewDimensionalPriceConfiguration { DimensionValues = ["string"] }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewDimensionalPriceConfiguration + { + DimensionValues = ["string"], + + DimensionalPriceGroupID = null, + ExternalDimensionalPriceGroupID = null, + }; + + Assert.Null(model.DimensionalPriceGroupID); + Assert.True(model.RawData.ContainsKey("dimensional_price_group_id")); + Assert.Null(model.ExternalDimensionalPriceGroupID); + Assert.True(model.RawData.ContainsKey("external_dimensional_price_group_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewDimensionalPriceConfiguration + { + DimensionValues = ["string"], + + DimensionalPriceGroupID = null, + ExternalDimensionalPriceGroupID = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingBulkPriceTest.cs b/src/Orb.Tests/Models/NewFloatingBulkPriceTest.cs new file mode 100644 index 00000000..45d7089c --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingBulkPriceTest.cs @@ -0,0 +1,649 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingBulkPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = + NewFloatingBulkPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = ModelType.Bulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkConfig, model.BulkConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = + NewFloatingBulkPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = ModelType.Bulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkConfig, deserialized.BulkConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingBulkPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingBulkPriceCadence.Annual)] + [InlineData(NewFloatingBulkPriceCadence.SemiAnnual)] + [InlineData(NewFloatingBulkPriceCadence.Monthly)] + [InlineData(NewFloatingBulkPriceCadence.Quarterly)] + [InlineData(NewFloatingBulkPriceCadence.OneTime)] + [InlineData(NewFloatingBulkPriceCadence.Custom)] + public void Validation_Works(NewFloatingBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingBulkPriceCadence.Annual)] + [InlineData(NewFloatingBulkPriceCadence.SemiAnnual)] + [InlineData(NewFloatingBulkPriceCadence.Monthly)] + [InlineData(NewFloatingBulkPriceCadence.Quarterly)] + [InlineData(NewFloatingBulkPriceCadence.OneTime)] + [InlineData(NewFloatingBulkPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ModelTypeTest : TestBase +{ + [Theory] + [InlineData(ModelType.Bulk)] + public void Validation_Works(ModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ModelType.Bulk)] + public void SerializationRoundtrip_Works(ModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingBulkWithProrationPriceTest.cs b/src/Orb.Tests/Models/NewFloatingBulkWithProrationPriceTest.cs new file mode 100644 index 00000000..a5f4c455 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingBulkWithProrationPriceTest.cs @@ -0,0 +1,893 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingBulkWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + BulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum expectedCadence = + NewFloatingBulkWithProrationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingBulkWithProrationPriceModelType.BulkWithProration; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingBulkWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithProrationConfig, model.BulkWithProrationConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum expectedCadence = + NewFloatingBulkWithProrationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingBulkWithProrationPriceModelType.BulkWithProration; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingBulkWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithProrationConfig, deserialized.BulkWithProrationConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class BulkWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class TierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class NewFloatingBulkWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Annual)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Monthly)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Quarterly)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.OneTime)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Custom)] + public void Validation_Works(NewFloatingBulkWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Annual)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Monthly)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Quarterly)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.OneTime)] + [InlineData(NewFloatingBulkWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingBulkWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingBulkWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingBulkWithProrationPriceModelType.BulkWithProration)] + public void Validation_Works(NewFloatingBulkWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingBulkWithProrationPriceModelType.BulkWithProration)] + public void SerializationRoundtrip_Works(NewFloatingBulkWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingBulkWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingBulkWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingBulkWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingBulkWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingBulkWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingCumulativeGroupedBulkPriceTest.cs b/src/Orb.Tests/Models/NewFloatingCumulativeGroupedBulkPriceTest.cs new file mode 100644 index 00000000..cae87655 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingCumulativeGroupedBulkPriceTest.cs @@ -0,0 +1,979 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingCumulativeGroupedBulkPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingCumulativeGroupedBulkPriceCadence.Annual; + CumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCumulativeGroupedBulkConfig, model.CumulativeGroupedBulkConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingCumulativeGroupedBulkPriceCadence.Annual; + CumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCumulativeGroupedBulkConfig, deserialized.CumulativeGroupedBulkConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingCumulativeGroupedBulkPrice + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingCumulativeGroupedBulkPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Annual)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.SemiAnnual)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Monthly)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Quarterly)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.OneTime)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Custom)] + public void Validation_Works(NewFloatingCumulativeGroupedBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Annual)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.SemiAnnual)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Monthly)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Quarterly)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.OneTime)] + [InlineData(NewFloatingCumulativeGroupedBulkPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingCumulativeGroupedBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedGroup, model.Group); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedGroup, deserialized.Group); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + model.Validate(); + } +} + +public class DimensionValueTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingCumulativeGroupedBulkPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk)] + public void Validation_Works(NewFloatingCumulativeGroupedBulkPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk)] + public void SerializationRoundtrip_Works( + NewFloatingCumulativeGroupedBulkPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingCumulativeGroupedBulkPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingGroupedAllocationPriceTest.cs b/src/Orb.Tests/Models/NewFloatingGroupedAllocationPriceTest.cs new file mode 100644 index 00000000..d9794aac --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingGroupedAllocationPriceTest.cs @@ -0,0 +1,783 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingGroupedAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingGroupedAllocationPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedAllocationPriceModelType.GroupedAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedGroupedAllocationConfig, model.GroupedAllocationConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingGroupedAllocationPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedAllocationPriceModelType.GroupedAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedGroupedAllocationConfig, deserialized.GroupedAllocationConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingGroupedAllocationPrice + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Annual)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Custom)] + public void Validation_Works(NewFloatingGroupedAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Annual)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingGroupedAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedOverageUnitRate, model.OverageUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedOverageUnitRate, deserialized.OverageUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedAllocationPriceModelType.GroupedAllocation)] + public void Validation_Works(NewFloatingGroupedAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedAllocationPriceModelType.GroupedAllocation)] + public void SerializationRoundtrip_Works(NewFloatingGroupedAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingGroupedAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingGroupedAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingGroupedAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingGroupedAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingGroupedAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingGroupedTieredPackagePriceTest.cs b/src/Orb.Tests/Models/NewFloatingGroupedTieredPackagePriceTest.cs new file mode 100644 index 00000000..1814e1ba --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingGroupedTieredPackagePriceTest.cs @@ -0,0 +1,923 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingGroupedTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingGroupedTieredPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedTieredPackageConfig expectedGroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedGroupedTieredPackageConfig, model.GroupedTieredPackageConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingGroupedTieredPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedTieredPackageConfig expectedGroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedGroupedTieredPackageConfig, deserialized.GroupedTieredPackageConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingGroupedTieredPackagePrice + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Annual)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Monthly)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.OneTime)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Custom)] + public void Validation_Works(NewFloatingGroupedTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Annual)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Monthly)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.OneTime)] + [InlineData(NewFloatingGroupedTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingGroupedTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class GroupedTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage)] + public void Validation_Works(NewFloatingGroupedTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage)] + public void SerializationRoundtrip_Works(NewFloatingGroupedTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingGroupedTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingGroupedTieredPriceTest.cs b/src/Orb.Tests/Models/NewFloatingGroupedTieredPriceTest.cs new file mode 100644 index 00000000..7ffcca43 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingGroupedTieredPriceTest.cs @@ -0,0 +1,899 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingGroupedTieredPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingGroupedTieredPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedTieredPriceModelType.GroupedTiered; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedGroupedTieredConfig, model.GroupedTieredConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingGroupedTieredPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedTieredPriceModelType.GroupedTiered; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedGroupedTieredConfig, deserialized.GroupedTieredConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingGroupedTieredPrice + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedTieredPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedTieredPriceCadence.Annual)] + [InlineData(NewFloatingGroupedTieredPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedTieredPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedTieredPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedTieredPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedTieredPriceCadence.Custom)] + public void Validation_Works(NewFloatingGroupedTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedTieredPriceCadence.Annual)] + [InlineData(NewFloatingGroupedTieredPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedTieredPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedTieredPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedTieredPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedTieredPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingGroupedTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class GroupedTieredConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedTieredPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedTieredPriceModelType.GroupedTiered)] + public void Validation_Works(NewFloatingGroupedTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedTieredPriceModelType.GroupedTiered)] + public void SerializationRoundtrip_Works(NewFloatingGroupedTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingGroupedTieredPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingGroupedTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingGroupedTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingGroupedTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingGroupedTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingGroupedWithMeteredMinimumPriceTest.cs b/src/Orb.Tests/Models/NewFloatingGroupedWithMeteredMinimumPriceTest.cs new file mode 100644 index 00000000..40be8321 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingGroupedWithMeteredMinimumPriceTest.cs @@ -0,0 +1,1103 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingGroupedWithMeteredMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + model.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + deserialized.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingGroupedWithMeteredMinimumPrice + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedWithMeteredMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Custom)] + public void Validation_Works(NewFloatingGroupedWithMeteredMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewFloatingGroupedWithMeteredMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, model.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, model.PricingKey); + Assert.Equal(expectedScalingFactors.Count, model.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], model.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, model.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, deserialized.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, deserialized.PricingKey); + Assert.Equal(expectedScalingFactors.Count, deserialized.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], deserialized.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, deserialized.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class ScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string expectedScalingFactorValue = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactorValue, model.ScalingFactorValue); + Assert.Equal(expectedScalingValue, model.ScalingValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedScalingFactorValue = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactorValue, deserialized.ScalingFactorValue); + Assert.Equal(expectedScalingValue, deserialized.ScalingValue); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + model.Validate(); + } +} + +public class UnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmountValue = "unit_amount"; + + Assert.Equal(expectedPricingValue, model.PricingValue); + Assert.Equal(expectedUnitAmountValue, model.UnitAmountValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmountValue = "unit_amount"; + + Assert.Equal(expectedPricingValue, deserialized.PricingValue); + Assert.Equal(expectedUnitAmountValue, deserialized.UnitAmountValue); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedWithMeteredMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum)] + public void Validation_Works(NewFloatingGroupedWithMeteredMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum)] + public void SerializationRoundtrip_Works( + NewFloatingGroupedWithMeteredMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingGroupedWithProratedMinimumPriceTest.cs b/src/Orb.Tests/Models/NewFloatingGroupedWithProratedMinimumPriceTest.cs new file mode 100644 index 00000000..2ee6b6fb --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingGroupedWithProratedMinimumPriceTest.cs @@ -0,0 +1,805 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingGroupedWithProratedMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingGroupedWithProratedMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + model.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingGroupedWithProratedMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + GroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + deserialized.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingGroupedWithProratedMinimumPrice + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedWithProratedMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Annual)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Custom)] + public void Validation_Works(NewFloatingGroupedWithProratedMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Annual)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewFloatingGroupedWithProratedMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedUnitRate, model.UnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedUnitRate, deserialized.UnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + model.Validate(); + } +} + +public class NewFloatingGroupedWithProratedMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum)] + public void Validation_Works(NewFloatingGroupedWithProratedMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum)] + public void SerializationRoundtrip_Works( + NewFloatingGroupedWithProratedMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingGroupedWithProratedMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingMatrixPriceTest.cs b/src/Orb.Tests/Models/NewFloatingMatrixPriceTest.cs new file mode 100644 index 00000000..5366ef9a --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingMatrixPriceTest.cs @@ -0,0 +1,699 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingMatrixPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingMatrixPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewFloatingMatrixPriceModelType.Matrix; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMatrixPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixConfig, model.MatrixConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingMatrixPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewFloatingMatrixPriceModelType.Matrix; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMatrixPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixConfig, deserialized.MatrixConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingMatrixPrice + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingMatrixPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMatrixPriceCadence.Annual)] + [InlineData(NewFloatingMatrixPriceCadence.SemiAnnual)] + [InlineData(NewFloatingMatrixPriceCadence.Monthly)] + [InlineData(NewFloatingMatrixPriceCadence.Quarterly)] + [InlineData(NewFloatingMatrixPriceCadence.OneTime)] + [InlineData(NewFloatingMatrixPriceCadence.Custom)] + public void Validation_Works(NewFloatingMatrixPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMatrixPriceCadence.Annual)] + [InlineData(NewFloatingMatrixPriceCadence.SemiAnnual)] + [InlineData(NewFloatingMatrixPriceCadence.Monthly)] + [InlineData(NewFloatingMatrixPriceCadence.Quarterly)] + [InlineData(NewFloatingMatrixPriceCadence.OneTime)] + [InlineData(NewFloatingMatrixPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingMatrixPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMatrixPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMatrixPriceModelType.Matrix)] + public void Validation_Works(NewFloatingMatrixPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMatrixPriceModelType.Matrix)] + public void SerializationRoundtrip_Works(NewFloatingMatrixPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMatrixPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingMatrixPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingMatrixPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingMatrixPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingMatrixPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingMatrixWithAllocationPriceTest.cs b/src/Orb.Tests/Models/NewFloatingMatrixWithAllocationPriceTest.cs new file mode 100644 index 00000000..b3c1f4f6 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingMatrixWithAllocationPriceTest.cs @@ -0,0 +1,721 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingMatrixWithAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingMatrixWithAllocationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMatrixWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixWithAllocationConfig, model.MatrixWithAllocationConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingMatrixWithAllocationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMatrixWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixWithAllocationConfig, deserialized.MatrixWithAllocationConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingMatrixWithAllocationPrice + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingMatrixWithAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Annual)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Monthly)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Quarterly)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.OneTime)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Custom)] + public void Validation_Works(NewFloatingMatrixWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Annual)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Monthly)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Quarterly)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.OneTime)] + [InlineData(NewFloatingMatrixWithAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingMatrixWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMatrixWithAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation)] + public void Validation_Works(NewFloatingMatrixWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation)] + public void SerializationRoundtrip_Works(NewFloatingMatrixWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMatrixWithAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingMatrixWithDisplayNamePriceTest.cs b/src/Orb.Tests/Models/NewFloatingMatrixWithDisplayNamePriceTest.cs new file mode 100644 index 00000000..f3950a41 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingMatrixWithDisplayNamePriceTest.cs @@ -0,0 +1,981 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingMatrixWithDisplayNamePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingMatrixWithDisplayNamePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + ApiEnum expectedModelType = + NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixWithDisplayNameConfig, model.MatrixWithDisplayNameConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingMatrixWithDisplayNamePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + ApiEnum expectedModelType = + NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixWithDisplayNameConfig, deserialized.MatrixWithDisplayNameConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingMatrixWithDisplayNamePrice + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingMatrixWithDisplayNamePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Annual)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.SemiAnnual)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Monthly)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Quarterly)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.OneTime)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Custom)] + public void Validation_Works(NewFloatingMatrixWithDisplayNamePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Annual)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.SemiAnnual)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Monthly)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Quarterly)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.OneTime)] + [InlineData(NewFloatingMatrixWithDisplayNamePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingMatrixWithDisplayNamePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, model.Dimension); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, deserialized.Dimension); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } +} + +public class MatrixWithDisplayNameConfigUnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, model.DimensionValue); + Assert.Equal(expectedDisplayName, model.DisplayName); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, deserialized.DimensionValue); + Assert.Equal(expectedDisplayName, deserialized.DisplayName); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingMatrixWithDisplayNamePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName)] + public void Validation_Works(NewFloatingMatrixWithDisplayNamePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName)] + public void SerializationRoundtrip_Works( + NewFloatingMatrixWithDisplayNamePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMatrixWithDisplayNamePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingMaxGroupTieredPackagePriceTest.cs b/src/Orb.Tests/Models/NewFloatingMaxGroupTieredPackagePriceTest.cs new file mode 100644 index 00000000..48190acf --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingMaxGroupTieredPackagePriceTest.cs @@ -0,0 +1,925 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingMaxGroupTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingMaxGroupTieredPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + ApiEnum expectedModelType = + NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMaxGroupTieredPackageConfig, model.MaxGroupTieredPackageConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingMaxGroupTieredPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + ApiEnum expectedModelType = + NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMaxGroupTieredPackageConfig, deserialized.MaxGroupTieredPackageConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingMaxGroupTieredPackagePrice + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingMaxGroupTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Annual)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Monthly)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.OneTime)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Custom)] + public void Validation_Works(NewFloatingMaxGroupTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Annual)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Monthly)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.OneTime)] + [InlineData(NewFloatingMaxGroupTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingMaxGroupTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class MaxGroupTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingMaxGroupTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage)] + public void Validation_Works(NewFloatingMaxGroupTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage)] + public void SerializationRoundtrip_Works( + NewFloatingMaxGroupTieredPackagePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMaxGroupTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingMinimumCompositePriceTest.cs b/src/Orb.Tests/Models/NewFloatingMinimumCompositePriceTest.cs new file mode 100644 index 00000000..ca8982cd --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingMinimumCompositePriceTest.cs @@ -0,0 +1,763 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingMinimumCompositePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingMinimumCompositePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + ApiEnum expectedModelType = + NewFloatingMinimumCompositePriceModelType.Minimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMinimumCompositePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMinimumConfig, model.MinimumConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingMinimumCompositePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + MinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + ApiEnum expectedModelType = + NewFloatingMinimumCompositePriceModelType.Minimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingMinimumCompositePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMinimumConfig, deserialized.MinimumConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingMinimumCompositePrice + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingMinimumCompositePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMinimumCompositePriceCadence.Annual)] + [InlineData(NewFloatingMinimumCompositePriceCadence.SemiAnnual)] + [InlineData(NewFloatingMinimumCompositePriceCadence.Monthly)] + [InlineData(NewFloatingMinimumCompositePriceCadence.Quarterly)] + [InlineData(NewFloatingMinimumCompositePriceCadence.OneTime)] + [InlineData(NewFloatingMinimumCompositePriceCadence.Custom)] + public void Validation_Works(NewFloatingMinimumCompositePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMinimumCompositePriceCadence.Annual)] + [InlineData(NewFloatingMinimumCompositePriceCadence.SemiAnnual)] + [InlineData(NewFloatingMinimumCompositePriceCadence.Monthly)] + [InlineData(NewFloatingMinimumCompositePriceCadence.Quarterly)] + [InlineData(NewFloatingMinimumCompositePriceCadence.OneTime)] + [InlineData(NewFloatingMinimumCompositePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingMinimumCompositePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MinimumConfig { MinimumAmount = "minimum_amount", Prorated = true }; + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedProrated, model.Prorated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MinimumConfig { MinimumAmount = "minimum_amount", Prorated = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MinimumConfig { MinimumAmount = "minimum_amount", Prorated = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedProrated, deserialized.Prorated); + } + + [Fact] + public void Validation_Works() + { + var model = new MinimumConfig { MinimumAmount = "minimum_amount", Prorated = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MinimumConfig { MinimumAmount = "minimum_amount" }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new MinimumConfig { MinimumAmount = "minimum_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new MinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new MinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + model.Validate(); + } +} + +public class NewFloatingMinimumCompositePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingMinimumCompositePriceModelType.Minimum)] + public void Validation_Works(NewFloatingMinimumCompositePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingMinimumCompositePriceModelType.Minimum)] + public void SerializationRoundtrip_Works(NewFloatingMinimumCompositePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingMinimumCompositePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingMinimumCompositePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingMinimumCompositePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingMinimumCompositePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingMinimumCompositePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingPackagePriceTest.cs b/src/Orb.Tests/Models/NewFloatingPackagePriceTest.cs new file mode 100644 index 00000000..930dade2 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingPackagePriceTest.cs @@ -0,0 +1,657 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingPackagePriceModelType.Package; + string expectedName = "Annual fee"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageConfig, model.PackageConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingPackagePriceModelType.Package; + string expectedName = "Annual fee"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageConfig, deserialized.PackageConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingPackagePrice + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingPackagePriceCadence.Annual)] + [InlineData(NewFloatingPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingPackagePriceCadence.Monthly)] + [InlineData(NewFloatingPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingPackagePriceCadence.OneTime)] + [InlineData(NewFloatingPackagePriceCadence.Custom)] + public void Validation_Works(NewFloatingPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingPackagePriceCadence.Annual)] + [InlineData(NewFloatingPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingPackagePriceCadence.Monthly)] + [InlineData(NewFloatingPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingPackagePriceCadence.OneTime)] + [InlineData(NewFloatingPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingPackagePriceModelType.Package)] + public void Validation_Works(NewFloatingPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingPackagePriceModelType.Package)] + public void SerializationRoundtrip_Works(NewFloatingPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingPackageWithAllocationPriceTest.cs b/src/Orb.Tests/Models/NewFloatingPackageWithAllocationPriceTest.cs new file mode 100644 index 00000000..3dd64887 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingPackageWithAllocationPriceTest.cs @@ -0,0 +1,787 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingPackageWithAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingPackageWithAllocationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation; + string expectedName = "Annual fee"; + PackageWithAllocationConfig expectedPackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingPackageWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageWithAllocationConfig, model.PackageWithAllocationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingPackageWithAllocationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation; + string expectedName = "Annual fee"; + PackageWithAllocationConfig expectedPackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingPackageWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageWithAllocationConfig, deserialized.PackageWithAllocationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingPackageWithAllocationPrice + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingPackageWithAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Annual)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Monthly)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Quarterly)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.OneTime)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Custom)] + public void Validation_Works(NewFloatingPackageWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Annual)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Monthly)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Quarterly)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.OneTime)] + [InlineData(NewFloatingPackageWithAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingPackageWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingPackageWithAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation)] + public void Validation_Works(NewFloatingPackageWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation)] + public void SerializationRoundtrip_Works( + NewFloatingPackageWithAllocationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedPackageAmount, model.PackageAmount); + Assert.Equal(expectedPackageSize, model.PackageSize); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedPackageAmount, deserialized.PackageAmount); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + } + + [Fact] + public void Validation_Works() + { + var model = new PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + model.Validate(); + } +} + +public class NewFloatingPackageWithAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingPackageWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingPackageWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingPackageWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingPackageWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingScalableMatrixWithTieredPricingPriceTest.cs b/src/Orb.Tests/Models/NewFloatingScalableMatrixWithTieredPricingPriceTest.cs new file mode 100644 index 00000000..47ba2f52 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingScalableMatrixWithTieredPricingPriceTest.cs @@ -0,0 +1,1345 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingScalableMatrixWithTieredPricingPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum< + string, + NewFloatingScalableMatrixWithTieredPricingPriceModelType + > expectedModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing; + string expectedName = "Annual fee"; + ScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + model.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum< + string, + NewFloatingScalableMatrixWithTieredPricingPriceModelType + > expectedModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing; + string expectedName = "Annual fee"; + ScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + deserialized.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingScalableMatrixWithTieredPricingPrice + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingScalableMatrixWithTieredPricingPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.SemiAnnual)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Monthly)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Quarterly)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.OneTime)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Custom)] + public void Validation_Works(NewFloatingScalableMatrixWithTieredPricingPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.SemiAnnual)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Monthly)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Quarterly)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.OneTime)] + [InlineData(NewFloatingScalableMatrixWithTieredPricingPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewFloatingScalableMatrixWithTieredPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingScalableMatrixWithTieredPricingPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing + )] + public void Validation_Works(NewFloatingScalableMatrixWithTieredPricingPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing + )] + public void SerializationRoundtrip_Works( + NewFloatingScalableMatrixWithTieredPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class MatrixScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingScalableMatrixWithUnitPricingPriceTest.cs b/src/Orb.Tests/Models/NewFloatingScalableMatrixWithUnitPricingPriceTest.cs new file mode 100644 index 00000000..670b9e4d --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingScalableMatrixWithUnitPricingPriceTest.cs @@ -0,0 +1,1209 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingScalableMatrixWithUnitPricingPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing; + string expectedName = "Annual fee"; + ScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + model.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing; + string expectedName = "Annual fee"; + ScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + deserialized.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingScalableMatrixWithUnitPricingPrice + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingScalableMatrixWithUnitPricingPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.SemiAnnual)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Monthly)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Quarterly)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.OneTime)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Custom)] + public void Validation_Works(NewFloatingScalableMatrixWithUnitPricingPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.SemiAnnual)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Monthly)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Quarterly)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.OneTime)] + [InlineData(NewFloatingScalableMatrixWithUnitPricingPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewFloatingScalableMatrixWithUnitPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingScalableMatrixWithUnitPricingPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing + )] + public void Validation_Works(NewFloatingScalableMatrixWithUnitPricingPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing + )] + public void SerializationRoundtrip_Works( + NewFloatingScalableMatrixWithUnitPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, model.UnitPrice); + Assert.Equal(expectedProrate, model.Prorate); + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, deserialized.UnitPrice); + Assert.Equal(expectedProrate, deserialized.Prorate); + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithUnitPricingConfigMatrixScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingThresholdTotalAmountPriceTest.cs b/src/Orb.Tests/Models/NewFloatingThresholdTotalAmountPriceTest.cs new file mode 100644 index 00000000..02888a32 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingThresholdTotalAmountPriceTest.cs @@ -0,0 +1,955 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingThresholdTotalAmountPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingThresholdTotalAmountPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount; + string expectedName = "Annual fee"; + ThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingThresholdTotalAmountPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedThresholdTotalAmountConfig, model.ThresholdTotalAmountConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingThresholdTotalAmountPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount; + string expectedName = "Annual fee"; + ThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingThresholdTotalAmountPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedThresholdTotalAmountConfig, deserialized.ThresholdTotalAmountConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingThresholdTotalAmountPrice + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingThresholdTotalAmountPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Annual)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.SemiAnnual)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Monthly)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Quarterly)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.OneTime)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Custom)] + public void Validation_Works(NewFloatingThresholdTotalAmountPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Annual)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.SemiAnnual)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Monthly)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Quarterly)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.OneTime)] + [InlineData(NewFloatingThresholdTotalAmountPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingThresholdTotalAmountPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingThresholdTotalAmountPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount)] + public void Validation_Works(NewFloatingThresholdTotalAmountPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount)] + public void SerializationRoundtrip_Works(NewFloatingThresholdTotalAmountPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, model.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], model.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, deserialized.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], deserialized.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + model.Validate(); + } +} + +public class ConsumptionTableTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ConsumptionTable { Threshold = "threshold", TotalAmount = "total_amount" }; + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedTotalAmount, model.TotalAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ConsumptionTable { Threshold = "threshold", TotalAmount = "total_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ConsumptionTable { Threshold = "threshold", TotalAmount = "total_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedTotalAmount, deserialized.TotalAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ConsumptionTable { Threshold = "threshold", TotalAmount = "total_amount" }; + + model.Validate(); + } +} + +public class NewFloatingThresholdTotalAmountPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingTieredPackagePriceTest.cs b/src/Orb.Tests/Models/NewFloatingTieredPackagePriceTest.cs new file mode 100644 index 00000000..bba335c4 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingTieredPackagePriceTest.cs @@ -0,0 +1,899 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingTieredPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredPackagePriceModelType.TieredPackage; + string expectedName = "Annual fee"; + TieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredPackageConfig, model.TieredPackageConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingTieredPackagePriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredPackagePriceModelType.TieredPackage; + string expectedName = "Annual fee"; + TieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredPackageConfig, deserialized.TieredPackageConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingTieredPackagePrice + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredPackagePriceCadence.Annual)] + [InlineData(NewFloatingTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredPackagePriceCadence.Monthly)] + [InlineData(NewFloatingTieredPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingTieredPackagePriceCadence.OneTime)] + [InlineData(NewFloatingTieredPackagePriceCadence.Custom)] + public void Validation_Works(NewFloatingTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredPackagePriceCadence.Annual)] + [InlineData(NewFloatingTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredPackagePriceCadence.Monthly)] + [InlineData(NewFloatingTieredPackagePriceCadence.Quarterly)] + [InlineData(NewFloatingTieredPackagePriceCadence.OneTime)] + [InlineData(NewFloatingTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredPackagePriceModelType.TieredPackage)] + public void Validation_Works(NewFloatingTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredPackagePriceModelType.TieredPackage)] + public void SerializationRoundtrip_Works(NewFloatingTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class TieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewFloatingTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingTieredPackageWithMinimumPriceTest.cs b/src/Orb.Tests/Models/NewFloatingTieredPackageWithMinimumPriceTest.cs new file mode 100644 index 00000000..373f263c --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingTieredPackageWithMinimumPriceTest.cs @@ -0,0 +1,1082 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingTieredPackageWithMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingTieredPackageWithMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum; + string expectedName = "Annual fee"; + TieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredPackageWithMinimumConfig, model.TieredPackageWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingTieredPackageWithMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum; + string expectedName = "Annual fee"; + TieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedTieredPackageWithMinimumConfig, + deserialized.TieredPackageWithMinimumConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingTieredPackageWithMinimumPrice + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingTieredPackageWithMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Annual)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Custom)] + public void Validation_Works(NewFloatingTieredPackageWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Annual)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingTieredPackageWithMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewFloatingTieredPackageWithMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingTieredPackageWithMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum)] + public void Validation_Works(NewFloatingTieredPackageWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum)] + public void SerializationRoundtrip_Works( + NewFloatingTieredPackageWithMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + model.Validate(); + } +} + +public class TieredPackageWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewFloatingTieredPackageWithMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingTieredPriceTest.cs b/src/Orb.Tests/Models/NewFloatingTieredPriceTest.cs new file mode 100644 index 00000000..3c868030 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingTieredPriceTest.cs @@ -0,0 +1,769 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingTieredPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingTieredPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredPriceModelType.Tiered; + string expectedName = "Annual fee"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredConfig, model.TieredConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingTieredPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredPriceModelType.Tiered; + string expectedName = "Annual fee"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredConfig, deserialized.TieredConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingTieredPrice + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingTieredPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredPriceCadence.Annual)] + [InlineData(NewFloatingTieredPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredPriceCadence.Monthly)] + [InlineData(NewFloatingTieredPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredPriceCadence.OneTime)] + [InlineData(NewFloatingTieredPriceCadence.Custom)] + public void Validation_Works(NewFloatingTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredPriceCadence.Annual)] + [InlineData(NewFloatingTieredPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredPriceCadence.Monthly)] + [InlineData(NewFloatingTieredPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredPriceCadence.OneTime)] + [InlineData(NewFloatingTieredPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingTieredPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredPriceModelType.Tiered)] + public void Validation_Works(NewFloatingTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredPriceModelType.Tiered)] + public void SerializationRoundtrip_Works(NewFloatingTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingTieredPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingTieredWithMinimumPriceTest.cs b/src/Orb.Tests/Models/NewFloatingTieredWithMinimumPriceTest.cs new file mode 100644 index 00000000..3dd129a2 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingTieredWithMinimumPriceTest.cs @@ -0,0 +1,1203 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingTieredWithMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingTieredWithMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum; + string expectedName = "Annual fee"; + TieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithMinimumConfig, model.TieredWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingTieredWithMinimumPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum; + string expectedName = "Annual fee"; + TieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithMinimumConfig, deserialized.TieredWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingTieredWithMinimumPrice + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingTieredWithMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Annual)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Custom)] + public void Validation_Works(NewFloatingTieredWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Annual)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Monthly)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.OneTime)] + [InlineData(NewFloatingTieredWithMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingTieredWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingTieredWithMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum)] + public void Validation_Works(NewFloatingTieredWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum)] + public void SerializationRoundtrip_Works(NewFloatingTieredWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, model.HideZeroAmountTiers); + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, deserialized.HideZeroAmountTiers); + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + model.Validate(); + } +} + +public class TieredWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingTieredWithMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingTieredWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingTieredWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingTieredWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingTieredWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingTieredWithProrationPriceTest.cs b/src/Orb.Tests/Models/NewFloatingTieredWithProrationPriceTest.cs new file mode 100644 index 00000000..f512f07b --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingTieredWithProrationPriceTest.cs @@ -0,0 +1,817 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingTieredWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingTieredWithProrationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredWithProrationPriceModelType.TieredWithProration; + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingTieredWithProrationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingTieredWithProrationPriceModelType.TieredWithProration; + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingTieredWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingTieredWithProrationPrice + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingTieredWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Annual)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Monthly)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.OneTime)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Custom)] + public void Validation_Works(NewFloatingTieredWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Annual)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Monthly)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Quarterly)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.OneTime)] + [InlineData(NewFloatingTieredWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingTieredWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingTieredWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingTieredWithProrationPriceModelType.TieredWithProration)] + public void Validation_Works(NewFloatingTieredWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingTieredWithProrationPriceModelType.TieredWithProration)] + public void SerializationRoundtrip_Works(NewFloatingTieredWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class TieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewFloatingTieredWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingTieredWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingTieredWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingTieredWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingTieredWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingUnitPriceTest.cs b/src/Orb.Tests/Models/NewFloatingUnitPriceTest.cs new file mode 100644 index 00000000..0dc20296 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingUnitPriceTest.cs @@ -0,0 +1,651 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingUnitPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingUnitPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingUnitPriceModelType.Unit; + string expectedName = "Annual fee"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingUnitPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitConfig, model.UnitConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingUnitPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingUnitPriceModelType.Unit; + string expectedName = "Annual fee"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingUnitPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitConfig, deserialized.UnitConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingUnitPrice + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingUnitPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingUnitPriceCadence.Annual)] + [InlineData(NewFloatingUnitPriceCadence.SemiAnnual)] + [InlineData(NewFloatingUnitPriceCadence.Monthly)] + [InlineData(NewFloatingUnitPriceCadence.Quarterly)] + [InlineData(NewFloatingUnitPriceCadence.OneTime)] + [InlineData(NewFloatingUnitPriceCadence.Custom)] + public void Validation_Works(NewFloatingUnitPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingUnitPriceCadence.Annual)] + [InlineData(NewFloatingUnitPriceCadence.SemiAnnual)] + [InlineData(NewFloatingUnitPriceCadence.Monthly)] + [InlineData(NewFloatingUnitPriceCadence.Quarterly)] + [InlineData(NewFloatingUnitPriceCadence.OneTime)] + [InlineData(NewFloatingUnitPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingUnitPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingUnitPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingUnitPriceModelType.Unit)] + public void Validation_Works(NewFloatingUnitPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingUnitPriceModelType.Unit)] + public void SerializationRoundtrip_Works(NewFloatingUnitPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingUnitPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingUnitPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingUnitPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingUnitPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingUnitPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingUnitWithPercentPriceTest.cs b/src/Orb.Tests/Models/NewFloatingUnitWithPercentPriceTest.cs new file mode 100644 index 00000000..440cbe87 --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingUnitWithPercentPriceTest.cs @@ -0,0 +1,717 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingUnitWithPercentPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingUnitWithPercentPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingUnitWithPercentPriceModelType.UnitWithPercent; + string expectedName = "Annual fee"; + UnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingUnitWithPercentPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitWithPercentConfig, model.UnitWithPercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingUnitWithPercentPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingUnitWithPercentPriceModelType.UnitWithPercent; + string expectedName = "Annual fee"; + UnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingUnitWithPercentPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitWithPercentConfig, deserialized.UnitWithPercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingUnitWithPercentPrice + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingUnitWithPercentPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Annual)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.SemiAnnual)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Monthly)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Quarterly)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.OneTime)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Custom)] + public void Validation_Works(NewFloatingUnitWithPercentPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Annual)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.SemiAnnual)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Monthly)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Quarterly)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.OneTime)] + [InlineData(NewFloatingUnitWithPercentPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingUnitWithPercentPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingUnitWithPercentPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingUnitWithPercentPriceModelType.UnitWithPercent)] + public void Validation_Works(NewFloatingUnitWithPercentPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingUnitWithPercentPriceModelType.UnitWithPercent)] + public void SerializationRoundtrip_Works(NewFloatingUnitWithPercentPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithPercentConfig { Percent = "percent", UnitAmount = "unit_amount" }; + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, model.Percent); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithPercentConfig { Percent = "percent", UnitAmount = "unit_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithPercentConfig { Percent = "percent", UnitAmount = "unit_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, deserialized.Percent); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithPercentConfig { Percent = "percent", UnitAmount = "unit_amount" }; + + model.Validate(); + } +} + +public class NewFloatingUnitWithPercentPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingUnitWithPercentPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingUnitWithPercentPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingUnitWithPercentPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingUnitWithPercentPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewFloatingUnitWithProrationPriceTest.cs b/src/Orb.Tests/Models/NewFloatingUnitWithProrationPriceTest.cs new file mode 100644 index 00000000..2e9dbe6b --- /dev/null +++ b/src/Orb.Tests/Models/NewFloatingUnitWithProrationPriceTest.cs @@ -0,0 +1,705 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewFloatingUnitWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + NewFloatingUnitWithProrationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingUnitWithProrationPriceModelType.UnitWithProration; + string expectedName = "Annual fee"; + UnitWithProrationConfig expectedUnitWithProrationConfig = new("unit_amount"); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingUnitWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitWithProrationConfig, model.UnitWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewFloatingUnitWithProrationPriceCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewFloatingUnitWithProrationPriceModelType.UnitWithProration; + string expectedName = "Annual fee"; + UnitWithProrationConfig expectedUnitWithProrationConfig = new("unit_amount"); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewFloatingUnitWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitWithProrationConfig, deserialized.UnitWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewFloatingUnitWithProrationPrice + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class NewFloatingUnitWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Annual)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Monthly)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Quarterly)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.OneTime)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Custom)] + public void Validation_Works(NewFloatingUnitWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Annual)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Monthly)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Quarterly)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.OneTime)] + [InlineData(NewFloatingUnitWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewFloatingUnitWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewFloatingUnitWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewFloatingUnitWithProrationPriceModelType.UnitWithProration)] + public void Validation_Works(NewFloatingUnitWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewFloatingUnitWithProrationPriceModelType.UnitWithProration)] + public void SerializationRoundtrip_Works(NewFloatingUnitWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + model.Validate(); + } +} + +public class NewFloatingUnitWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewFloatingUnitWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewFloatingUnitWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewFloatingUnitWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewFloatingUnitWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewMaximumTest.cs b/src/Orb.Tests/Models/NewMaximumTest.cs new file mode 100644 index 00000000..12e11a09 --- /dev/null +++ b/src/Orb.Tests/Models/NewMaximumTest.cs @@ -0,0 +1,791 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewMaximumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + }; + + ApiEnum expectedAdjustmentType = + NewMaximumAdjustmentType.Maximum; + string expectedMaximumAmount = "maximum_amount"; + ApiEnum expectedAppliesToAll = NewMaximumAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = NewMaximumPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedAppliesToAll, model.AppliesToAll); + Assert.NotNull(model.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, model.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], model.AppliesToItemIDs[i]); + } + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPriceType, model.PriceType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedAdjustmentType = + NewMaximumAdjustmentType.Maximum; + string expectedMaximumAmount = "maximum_amount"; + ApiEnum expectedAppliesToAll = NewMaximumAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = NewMaximumPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedAppliesToAll, deserialized.AppliesToAll); + Assert.NotNull(deserialized.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, deserialized.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], deserialized.AppliesToItemIDs[i]); + } + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPriceType, deserialized.PriceType); + } + + [Fact] + public void Validation_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMaximumPriceType.Usage, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMaximumPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMaximumPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMaximumPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + IsInvoiceLevel = true, + }; + + Assert.Null(model.AppliesToAll); + Assert.False(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.False(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.False(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + IsInvoiceLevel = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + Assert.Null(model.AppliesToAll); + Assert.True(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.True(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.True(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewMaximum + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + model.Validate(); + } +} + +public class NewMaximumAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(NewMaximumAdjustmentType.Maximum)] + public void Validation_Works(NewMaximumAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMaximumAdjustmentType.Maximum)] + public void SerializationRoundtrip_Works(NewMaximumAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMaximumAppliesToAllTest : TestBase +{ + [Theory] + [InlineData(NewMaximumAppliesToAll.True)] + public void Validation_Works(NewMaximumAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMaximumAppliesToAll.True)] + public void SerializationRoundtrip_Works(NewMaximumAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMaximumFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewMaximumFilter + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = NewMaximumFilterField.PriceID; + ApiEnum expectedOperator = + NewMaximumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewMaximumFilter + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewMaximumFilter + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = NewMaximumFilterField.PriceID; + ApiEnum expectedOperator = + NewMaximumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewMaximumFilter + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class NewMaximumFilterFieldTest : TestBase +{ + [Theory] + [InlineData(NewMaximumFilterField.PriceID)] + [InlineData(NewMaximumFilterField.ItemID)] + [InlineData(NewMaximumFilterField.PriceType)] + [InlineData(NewMaximumFilterField.Currency)] + [InlineData(NewMaximumFilterField.PricingUnitID)] + public void Validation_Works(NewMaximumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMaximumFilterField.PriceID)] + [InlineData(NewMaximumFilterField.ItemID)] + [InlineData(NewMaximumFilterField.PriceType)] + [InlineData(NewMaximumFilterField.Currency)] + [InlineData(NewMaximumFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(NewMaximumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMaximumFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(NewMaximumFilterOperator.Includes)] + [InlineData(NewMaximumFilterOperator.Excludes)] + public void Validation_Works(NewMaximumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMaximumFilterOperator.Includes)] + [InlineData(NewMaximumFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(NewMaximumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMaximumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(NewMaximumPriceType.Usage)] + [InlineData(NewMaximumPriceType.FixedInAdvance)] + [InlineData(NewMaximumPriceType.FixedInArrears)] + [InlineData(NewMaximumPriceType.Fixed)] + [InlineData(NewMaximumPriceType.InArrears)] + public void Validation_Works(NewMaximumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMaximumPriceType.Usage)] + [InlineData(NewMaximumPriceType.FixedInAdvance)] + [InlineData(NewMaximumPriceType.FixedInArrears)] + [InlineData(NewMaximumPriceType.Fixed)] + [InlineData(NewMaximumPriceType.InArrears)] + public void SerializationRoundtrip_Works(NewMaximumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewMinimumTest.cs b/src/Orb.Tests/Models/NewMinimumTest.cs new file mode 100644 index 00000000..433765ea --- /dev/null +++ b/src/Orb.Tests/Models/NewMinimumTest.cs @@ -0,0 +1,807 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewMinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + }; + + ApiEnum expectedAdjustmentType = + NewMinimumAdjustmentType.Minimum; + string expectedItemID = "item_id"; + string expectedMinimumAmount = "minimum_amount"; + ApiEnum expectedAppliesToAll = NewMinimumAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = NewMinimumPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedAppliesToAll, model.AppliesToAll); + Assert.NotNull(model.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, model.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], model.AppliesToItemIDs[i]); + } + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPriceType, model.PriceType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedAdjustmentType = + NewMinimumAdjustmentType.Minimum; + string expectedItemID = "item_id"; + string expectedMinimumAmount = "minimum_amount"; + ApiEnum expectedAppliesToAll = NewMinimumAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = NewMinimumPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedAppliesToAll, deserialized.AppliesToAll); + Assert.NotNull(deserialized.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, deserialized.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], deserialized.AppliesToItemIDs[i]); + } + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPriceType, deserialized.PriceType); + } + + [Fact] + public void Validation_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMinimumPriceType.Usage, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMinimumPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMinimumPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewMinimumPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + IsInvoiceLevel = true, + }; + + Assert.Null(model.AppliesToAll); + Assert.False(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.False(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.False(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + IsInvoiceLevel = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + Assert.Null(model.AppliesToAll); + Assert.True(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.True(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.True(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewMinimum + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + model.Validate(); + } +} + +public class NewMinimumAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(NewMinimumAdjustmentType.Minimum)] + public void Validation_Works(NewMinimumAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMinimumAdjustmentType.Minimum)] + public void SerializationRoundtrip_Works(NewMinimumAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMinimumAppliesToAllTest : TestBase +{ + [Theory] + [InlineData(NewMinimumAppliesToAll.True)] + public void Validation_Works(NewMinimumAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMinimumAppliesToAll.True)] + public void SerializationRoundtrip_Works(NewMinimumAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMinimumFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewMinimumFilter + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = NewMinimumFilterField.PriceID; + ApiEnum expectedOperator = + NewMinimumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewMinimumFilter + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewMinimumFilter + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = NewMinimumFilterField.PriceID; + ApiEnum expectedOperator = + NewMinimumFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewMinimumFilter + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class NewMinimumFilterFieldTest : TestBase +{ + [Theory] + [InlineData(NewMinimumFilterField.PriceID)] + [InlineData(NewMinimumFilterField.ItemID)] + [InlineData(NewMinimumFilterField.PriceType)] + [InlineData(NewMinimumFilterField.Currency)] + [InlineData(NewMinimumFilterField.PricingUnitID)] + public void Validation_Works(NewMinimumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMinimumFilterField.PriceID)] + [InlineData(NewMinimumFilterField.ItemID)] + [InlineData(NewMinimumFilterField.PriceType)] + [InlineData(NewMinimumFilterField.Currency)] + [InlineData(NewMinimumFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(NewMinimumFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMinimumFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(NewMinimumFilterOperator.Includes)] + [InlineData(NewMinimumFilterOperator.Excludes)] + public void Validation_Works(NewMinimumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMinimumFilterOperator.Includes)] + [InlineData(NewMinimumFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(NewMinimumFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewMinimumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(NewMinimumPriceType.Usage)] + [InlineData(NewMinimumPriceType.FixedInAdvance)] + [InlineData(NewMinimumPriceType.FixedInArrears)] + [InlineData(NewMinimumPriceType.Fixed)] + [InlineData(NewMinimumPriceType.InArrears)] + public void Validation_Works(NewMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewMinimumPriceType.Usage)] + [InlineData(NewMinimumPriceType.FixedInAdvance)] + [InlineData(NewMinimumPriceType.FixedInArrears)] + [InlineData(NewMinimumPriceType.Fixed)] + [InlineData(NewMinimumPriceType.InArrears)] + public void SerializationRoundtrip_Works(NewMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPercentageDiscountTest.cs b/src/Orb.Tests/Models/NewPercentageDiscountTest.cs new file mode 100644 index 00000000..05b482f1 --- /dev/null +++ b/src/Orb.Tests/Models/NewPercentageDiscountTest.cs @@ -0,0 +1,795 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPercentageDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + + ApiEnum expectedAdjustmentType = + NewPercentageDiscountAdjustmentType.PercentageDiscount; + double expectedPercentageDiscount = 0; + ApiEnum expectedAppliesToAll = + NewPercentageDiscountAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = + NewPercentageDiscountPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.Equal(expectedAppliesToAll, model.AppliesToAll); + Assert.NotNull(model.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, model.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], model.AppliesToItemIDs[i]); + } + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPriceType, model.PriceType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedAdjustmentType = + NewPercentageDiscountAdjustmentType.PercentageDiscount; + double expectedPercentageDiscount = 0; + ApiEnum expectedAppliesToAll = + NewPercentageDiscountAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = + NewPercentageDiscountPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.Equal(expectedAppliesToAll, deserialized.AppliesToAll); + Assert.NotNull(deserialized.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, deserialized.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], deserialized.AppliesToItemIDs[i]); + } + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPriceType, deserialized.PriceType); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewPercentageDiscountPriceType.Usage, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewPercentageDiscountPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewPercentageDiscountPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewPercentageDiscountPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + IsInvoiceLevel = true, + }; + + Assert.Null(model.AppliesToAll); + Assert.False(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.False(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.False(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + IsInvoiceLevel = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + Assert.Null(model.AppliesToAll); + Assert.True(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.True(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.True(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPercentageDiscount + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + model.Validate(); + } +} + +public class NewPercentageDiscountAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(NewPercentageDiscountAdjustmentType.PercentageDiscount)] + public void Validation_Works(NewPercentageDiscountAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPercentageDiscountAdjustmentType.PercentageDiscount)] + public void SerializationRoundtrip_Works(NewPercentageDiscountAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPercentageDiscountAppliesToAllTest : TestBase +{ + [Theory] + [InlineData(NewPercentageDiscountAppliesToAll.True)] + public void Validation_Works(NewPercentageDiscountAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPercentageDiscountAppliesToAll.True)] + public void SerializationRoundtrip_Works(NewPercentageDiscountAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPercentageDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPercentageDiscountFilter + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + NewPercentageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + NewPercentageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPercentageDiscountFilter + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPercentageDiscountFilter + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + NewPercentageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + NewPercentageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPercentageDiscountFilter + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class NewPercentageDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(NewPercentageDiscountFilterField.PriceID)] + [InlineData(NewPercentageDiscountFilterField.ItemID)] + [InlineData(NewPercentageDiscountFilterField.PriceType)] + [InlineData(NewPercentageDiscountFilterField.Currency)] + [InlineData(NewPercentageDiscountFilterField.PricingUnitID)] + public void Validation_Works(NewPercentageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPercentageDiscountFilterField.PriceID)] + [InlineData(NewPercentageDiscountFilterField.ItemID)] + [InlineData(NewPercentageDiscountFilterField.PriceType)] + [InlineData(NewPercentageDiscountFilterField.Currency)] + [InlineData(NewPercentageDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(NewPercentageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPercentageDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(NewPercentageDiscountFilterOperator.Includes)] + [InlineData(NewPercentageDiscountFilterOperator.Excludes)] + public void Validation_Works(NewPercentageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPercentageDiscountFilterOperator.Includes)] + [InlineData(NewPercentageDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(NewPercentageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPercentageDiscountPriceTypeTest : TestBase +{ + [Theory] + [InlineData(NewPercentageDiscountPriceType.Usage)] + [InlineData(NewPercentageDiscountPriceType.FixedInAdvance)] + [InlineData(NewPercentageDiscountPriceType.FixedInArrears)] + [InlineData(NewPercentageDiscountPriceType.Fixed)] + [InlineData(NewPercentageDiscountPriceType.InArrears)] + public void Validation_Works(NewPercentageDiscountPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPercentageDiscountPriceType.Usage)] + [InlineData(NewPercentageDiscountPriceType.FixedInAdvance)] + [InlineData(NewPercentageDiscountPriceType.FixedInArrears)] + [InlineData(NewPercentageDiscountPriceType.Fixed)] + [InlineData(NewPercentageDiscountPriceType.InArrears)] + public void SerializationRoundtrip_Works(NewPercentageDiscountPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanBulkPriceTest.cs b/src/Orb.Tests/Models/NewPlanBulkPriceTest.cs new file mode 100644 index 00000000..669c9186 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanBulkPriceTest.cs @@ -0,0 +1,671 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanBulkPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = NewPlanBulkPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanBulkPriceModelType.Bulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkConfig, model.BulkConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = NewPlanBulkPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanBulkPriceModelType.Bulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkConfig, deserialized.BulkConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanBulkPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanBulkPriceCadence.Annual)] + [InlineData(NewPlanBulkPriceCadence.SemiAnnual)] + [InlineData(NewPlanBulkPriceCadence.Monthly)] + [InlineData(NewPlanBulkPriceCadence.Quarterly)] + [InlineData(NewPlanBulkPriceCadence.OneTime)] + [InlineData(NewPlanBulkPriceCadence.Custom)] + public void Validation_Works(NewPlanBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanBulkPriceCadence.Annual)] + [InlineData(NewPlanBulkPriceCadence.SemiAnnual)] + [InlineData(NewPlanBulkPriceCadence.Monthly)] + [InlineData(NewPlanBulkPriceCadence.Quarterly)] + [InlineData(NewPlanBulkPriceCadence.OneTime)] + [InlineData(NewPlanBulkPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanBulkPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanBulkPriceModelType.Bulk)] + public void Validation_Works(NewPlanBulkPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanBulkPriceModelType.Bulk)] + public void SerializationRoundtrip_Works(NewPlanBulkPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanBulkPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanBulkWithProrationPriceTest.cs b/src/Orb.Tests/Models/NewPlanBulkWithProrationPriceTest.cs new file mode 100644 index 00000000..8ab5b40d --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanBulkWithProrationPriceTest.cs @@ -0,0 +1,937 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanBulkWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + NewPlanBulkWithProrationPriceBulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum expectedCadence = + NewPlanBulkWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanBulkWithProrationPriceModelType.BulkWithProration; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanBulkWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithProrationConfig, model.BulkWithProrationConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + NewPlanBulkWithProrationPriceBulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum expectedCadence = + NewPlanBulkWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanBulkWithProrationPriceModelType.BulkWithProration; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanBulkWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithProrationConfig, deserialized.BulkWithProrationConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanBulkWithProrationPriceBulkWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanBulkWithProrationPriceBulkWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanBulkWithProrationPriceBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class NewPlanBulkWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanBulkWithProrationPriceCadence.Annual)] + [InlineData(NewPlanBulkWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewPlanBulkWithProrationPriceCadence.Monthly)] + [InlineData(NewPlanBulkWithProrationPriceCadence.Quarterly)] + [InlineData(NewPlanBulkWithProrationPriceCadence.OneTime)] + [InlineData(NewPlanBulkWithProrationPriceCadence.Custom)] + public void Validation_Works(NewPlanBulkWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanBulkWithProrationPriceCadence.Annual)] + [InlineData(NewPlanBulkWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewPlanBulkWithProrationPriceCadence.Monthly)] + [InlineData(NewPlanBulkWithProrationPriceCadence.Quarterly)] + [InlineData(NewPlanBulkWithProrationPriceCadence.OneTime)] + [InlineData(NewPlanBulkWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanBulkWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanBulkWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanBulkWithProrationPriceModelType.BulkWithProration)] + public void Validation_Works(NewPlanBulkWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanBulkWithProrationPriceModelType.BulkWithProration)] + public void SerializationRoundtrip_Works(NewPlanBulkWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanBulkWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanBulkWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanBulkWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanBulkWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanBulkWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanCumulativeGroupedBulkPriceTest.cs b/src/Orb.Tests/Models/NewPlanCumulativeGroupedBulkPriceTest.cs new file mode 100644 index 00000000..75add131 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanCumulativeGroupedBulkPriceTest.cs @@ -0,0 +1,1006 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanCumulativeGroupedBulkPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanCumulativeGroupedBulkPriceCadence.Annual; + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = + new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanCumulativeGroupedBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCumulativeGroupedBulkConfig, model.CumulativeGroupedBulkConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanCumulativeGroupedBulkPriceCadence.Annual; + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = + new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanCumulativeGroupedBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCumulativeGroupedBulkConfig, deserialized.CumulativeGroupedBulkConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanCumulativeGroupedBulkPrice + { + Cadence = NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanCumulativeGroupedBulkPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Annual)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.SemiAnnual)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Monthly)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Quarterly)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.OneTime)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Custom)] + public void Validation_Works(NewPlanCumulativeGroupedBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Annual)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.SemiAnnual)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Monthly)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Quarterly)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.OneTime)] + [InlineData(NewPlanCumulativeGroupedBulkPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanCumulativeGroupedBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedGroup, model.Group); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedGroup, deserialized.Group); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + model.Validate(); + } +} + +public class NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValueTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanCumulativeGroupedBulkPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk)] + public void Validation_Works(NewPlanCumulativeGroupedBulkPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk)] + public void SerializationRoundtrip_Works(NewPlanCumulativeGroupedBulkPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanCumulativeGroupedBulkPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanGroupedAllocationPriceTest.cs b/src/Orb.Tests/Models/NewPlanGroupedAllocationPriceTest.cs new file mode 100644 index 00000000..fcfb4fe7 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanGroupedAllocationPriceTest.cs @@ -0,0 +1,799 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanGroupedAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanGroupedAllocationPriceCadence.Annual; + NewPlanGroupedAllocationPriceGroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedAllocationPriceModelType.GroupedAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedGroupedAllocationConfig, model.GroupedAllocationConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanGroupedAllocationPriceCadence.Annual; + NewPlanGroupedAllocationPriceGroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedAllocationPriceModelType.GroupedAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedGroupedAllocationConfig, deserialized.GroupedAllocationConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanGroupedAllocationPrice + { + Cadence = NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanGroupedAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedAllocationPriceCadence.Annual)] + [InlineData(NewPlanGroupedAllocationPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedAllocationPriceCadence.Monthly)] + [InlineData(NewPlanGroupedAllocationPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedAllocationPriceCadence.OneTime)] + [InlineData(NewPlanGroupedAllocationPriceCadence.Custom)] + public void Validation_Works(NewPlanGroupedAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedAllocationPriceCadence.Annual)] + [InlineData(NewPlanGroupedAllocationPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedAllocationPriceCadence.Monthly)] + [InlineData(NewPlanGroupedAllocationPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedAllocationPriceCadence.OneTime)] + [InlineData(NewPlanGroupedAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanGroupedAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedAllocationPriceGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedAllocationPriceGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedOverageUnitRate, model.OverageUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedAllocationPriceGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedAllocationPriceGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedOverageUnitRate, deserialized.OverageUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedAllocationPriceGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + model.Validate(); + } +} + +public class NewPlanGroupedAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedAllocationPriceModelType.GroupedAllocation)] + public void Validation_Works(NewPlanGroupedAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedAllocationPriceModelType.GroupedAllocation)] + public void SerializationRoundtrip_Works(NewPlanGroupedAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanGroupedAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanGroupedAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanGroupedAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanGroupedAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanGroupedTieredPackagePriceTest.cs b/src/Orb.Tests/Models/NewPlanGroupedTieredPackagePriceTest.cs new file mode 100644 index 00000000..a8eb9011 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanGroupedTieredPackagePriceTest.cs @@ -0,0 +1,951 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanGroupedTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanGroupedTieredPackagePriceCadence.Annual; + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig expectedGroupedTieredPackageConfig = + new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedGroupedTieredPackageConfig, model.GroupedTieredPackageConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanGroupedTieredPackagePriceCadence.Annual; + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig expectedGroupedTieredPackageConfig = + new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedGroupedTieredPackageConfig, deserialized.GroupedTieredPackageConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanGroupedTieredPackagePrice + { + Cadence = NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanGroupedTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Annual)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Monthly)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Quarterly)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.OneTime)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Custom)] + public void Validation_Works(NewPlanGroupedTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Annual)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Monthly)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Quarterly)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.OneTime)] + [InlineData(NewPlanGroupedTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanGroupedTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewPlanGroupedTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage)] + public void Validation_Works(NewPlanGroupedTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage)] + public void SerializationRoundtrip_Works(NewPlanGroupedTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanGroupedTieredPriceTest.cs b/src/Orb.Tests/Models/NewPlanGroupedTieredPriceTest.cs new file mode 100644 index 00000000..dc748e5f --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanGroupedTieredPriceTest.cs @@ -0,0 +1,913 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanGroupedTieredPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanGroupedTieredPriceCadence.Annual; + NewPlanGroupedTieredPriceGroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedTieredPriceModelType.GroupedTiered; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedGroupedTieredConfig, model.GroupedTieredConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanGroupedTieredPriceCadence.Annual; + NewPlanGroupedTieredPriceGroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedTieredPriceModelType.GroupedTiered; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedGroupedTieredConfig, deserialized.GroupedTieredConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanGroupedTieredPrice + { + Cadence = NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanGroupedTieredPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedTieredPriceCadence.Annual)] + [InlineData(NewPlanGroupedTieredPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedTieredPriceCadence.Monthly)] + [InlineData(NewPlanGroupedTieredPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedTieredPriceCadence.OneTime)] + [InlineData(NewPlanGroupedTieredPriceCadence.Custom)] + public void Validation_Works(NewPlanGroupedTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedTieredPriceCadence.Annual)] + [InlineData(NewPlanGroupedTieredPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedTieredPriceCadence.Monthly)] + [InlineData(NewPlanGroupedTieredPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedTieredPriceCadence.OneTime)] + [InlineData(NewPlanGroupedTieredPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanGroupedTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedTieredPriceGroupedTieredConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanGroupedTieredPriceGroupedTieredConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedTieredPriceGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanGroupedTieredPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedTieredPriceModelType.GroupedTiered)] + public void Validation_Works(NewPlanGroupedTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedTieredPriceModelType.GroupedTiered)] + public void SerializationRoundtrip_Works(NewPlanGroupedTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedTieredPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanGroupedTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanGroupedTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanGroupedTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanGroupedTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanGroupedWithMeteredMinimumPriceTest.cs b/src/Orb.Tests/Models/NewPlanGroupedWithMeteredMinimumPriceTest.cs new file mode 100644 index 00000000..bb657071 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanGroupedWithMeteredMinimumPriceTest.cs @@ -0,0 +1,1125 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanGroupedWithMeteredMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanGroupedWithMeteredMinimumPriceCadence.Annual; + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = + new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + model.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanGroupedWithMeteredMinimumPriceCadence.Annual; + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = + new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + deserialized.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPrice + { + Cadence = NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanGroupedWithMeteredMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Annual)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Monthly)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.OneTime)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Custom)] + public void Validation_Works(NewPlanGroupedWithMeteredMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Annual)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Monthly)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.OneTime)] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanGroupedWithMeteredMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, model.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, model.PricingKey); + Assert.Equal(expectedScalingFactors.Count, model.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], model.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, model.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, deserialized.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, deserialized.PricingKey); + Assert.Equal(expectedScalingFactors.Count, deserialized.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], deserialized.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, deserialized.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactorTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string expectedScalingFactor = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedScalingValue, model.ScalingValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedScalingFactor = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedScalingValue, deserialized.ScalingValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + model.Validate(); + } +} + +public class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmountTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPricingValue, model.PricingValue); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPricingValue, deserialized.PricingValue); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanGroupedWithMeteredMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum)] + public void Validation_Works(NewPlanGroupedWithMeteredMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum)] + public void SerializationRoundtrip_Works( + NewPlanGroupedWithMeteredMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedWithMeteredMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanGroupedWithProratedMinimumPriceTest.cs b/src/Orb.Tests/Models/NewPlanGroupedWithProratedMinimumPriceTest.cs new file mode 100644 index 00000000..2b4e6e42 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanGroupedWithProratedMinimumPriceTest.cs @@ -0,0 +1,817 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanGroupedWithProratedMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanGroupedWithProratedMinimumPriceCadence.Annual; + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = + new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + model.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanGroupedWithProratedMinimumPriceCadence.Annual; + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = + new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + deserialized.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPrice + { + Cadence = NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanGroupedWithProratedMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Annual)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Monthly)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.OneTime)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Custom)] + public void Validation_Works(NewPlanGroupedWithProratedMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Annual)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Monthly)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.OneTime)] + [InlineData(NewPlanGroupedWithProratedMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanGroupedWithProratedMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedUnitRate, model.UnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedUnitRate, deserialized.UnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + model.Validate(); + } +} + +public class NewPlanGroupedWithProratedMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum)] + public void Validation_Works(NewPlanGroupedWithProratedMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum)] + public void SerializationRoundtrip_Works( + NewPlanGroupedWithProratedMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanGroupedWithProratedMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanMatrixPriceTest.cs b/src/Orb.Tests/Models/NewPlanMatrixPriceTest.cs new file mode 100644 index 00000000..e7f618fd --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanMatrixPriceTest.cs @@ -0,0 +1,719 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanMatrixPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanMatrixPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewPlanMatrixPriceModelType.Matrix; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMatrixPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixConfig, model.MatrixConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanMatrixPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewPlanMatrixPriceModelType.Matrix; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMatrixPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixConfig, deserialized.MatrixConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanMatrixPrice + { + Cadence = NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanMatrixPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanMatrixPriceCadence.Annual)] + [InlineData(NewPlanMatrixPriceCadence.SemiAnnual)] + [InlineData(NewPlanMatrixPriceCadence.Monthly)] + [InlineData(NewPlanMatrixPriceCadence.Quarterly)] + [InlineData(NewPlanMatrixPriceCadence.OneTime)] + [InlineData(NewPlanMatrixPriceCadence.Custom)] + public void Validation_Works(NewPlanMatrixPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMatrixPriceCadence.Annual)] + [InlineData(NewPlanMatrixPriceCadence.SemiAnnual)] + [InlineData(NewPlanMatrixPriceCadence.Monthly)] + [InlineData(NewPlanMatrixPriceCadence.Quarterly)] + [InlineData(NewPlanMatrixPriceCadence.OneTime)] + [InlineData(NewPlanMatrixPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanMatrixPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMatrixPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanMatrixPriceModelType.Matrix)] + public void Validation_Works(NewPlanMatrixPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMatrixPriceModelType.Matrix)] + public void SerializationRoundtrip_Works(NewPlanMatrixPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMatrixPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanMatrixPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanMatrixPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanMatrixPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanMatrixPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanMatrixWithAllocationPriceTest.cs b/src/Orb.Tests/Models/NewPlanMatrixWithAllocationPriceTest.cs new file mode 100644 index 00000000..205652c2 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanMatrixWithAllocationPriceTest.cs @@ -0,0 +1,735 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanMatrixWithAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanMatrixWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMatrixWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixWithAllocationConfig, model.MatrixWithAllocationConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanMatrixWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMatrixWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixWithAllocationConfig, deserialized.MatrixWithAllocationConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanMatrixWithAllocationPrice + { + Cadence = NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanMatrixWithAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Annual)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Monthly)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Quarterly)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.OneTime)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Custom)] + public void Validation_Works(NewPlanMatrixWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Annual)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Monthly)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Quarterly)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.OneTime)] + [InlineData(NewPlanMatrixWithAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanMatrixWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMatrixWithAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation)] + public void Validation_Works(NewPlanMatrixWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation)] + public void SerializationRoundtrip_Works(NewPlanMatrixWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMatrixWithAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanMatrixWithDisplayNamePriceTest.cs b/src/Orb.Tests/Models/NewPlanMatrixWithDisplayNamePriceTest.cs new file mode 100644 index 00000000..1313e4c3 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanMatrixWithDisplayNamePriceTest.cs @@ -0,0 +1,1005 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanMatrixWithDisplayNamePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanMatrixWithDisplayNamePriceCadence.Annual; + string expectedItemID = "item_id"; + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = + new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + ApiEnum expectedModelType = + NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMatrixWithDisplayNamePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixWithDisplayNameConfig, model.MatrixWithDisplayNameConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanMatrixWithDisplayNamePriceCadence.Annual; + string expectedItemID = "item_id"; + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = + new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + ApiEnum expectedModelType = + NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMatrixWithDisplayNamePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixWithDisplayNameConfig, deserialized.MatrixWithDisplayNameConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanMatrixWithDisplayNamePrice + { + Cadence = NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanMatrixWithDisplayNamePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Annual)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.SemiAnnual)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Monthly)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Quarterly)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.OneTime)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Custom)] + public void Validation_Works(NewPlanMatrixWithDisplayNamePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Annual)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.SemiAnnual)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Monthly)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Quarterly)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.OneTime)] + [InlineData(NewPlanMatrixWithDisplayNamePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanMatrixWithDisplayNamePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, model.Dimension); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, deserialized.Dimension); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, model.DimensionValue); + Assert.Equal(expectedDisplayName, model.DisplayName); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, deserialized.DimensionValue); + Assert.Equal(expectedDisplayName, deserialized.DisplayName); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanMatrixWithDisplayNamePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName)] + public void Validation_Works(NewPlanMatrixWithDisplayNamePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName)] + public void SerializationRoundtrip_Works(NewPlanMatrixWithDisplayNamePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMatrixWithDisplayNamePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanMaxGroupTieredPackagePriceTest.cs b/src/Orb.Tests/Models/NewPlanMaxGroupTieredPackagePriceTest.cs new file mode 100644 index 00000000..f0652056 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanMaxGroupTieredPackagePriceTest.cs @@ -0,0 +1,951 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanMaxGroupTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanMaxGroupTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = + new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + ApiEnum expectedModelType = + NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMaxGroupTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMaxGroupTieredPackageConfig, model.MaxGroupTieredPackageConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanMaxGroupTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = + new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + ApiEnum expectedModelType = + NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMaxGroupTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMaxGroupTieredPackageConfig, deserialized.MaxGroupTieredPackageConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanMaxGroupTieredPackagePrice + { + Cadence = NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanMaxGroupTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Annual)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Monthly)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Quarterly)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.OneTime)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Custom)] + public void Validation_Works(NewPlanMaxGroupTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Annual)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Monthly)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Quarterly)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.OneTime)] + [InlineData(NewPlanMaxGroupTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanMaxGroupTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanMaxGroupTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage)] + public void Validation_Works(NewPlanMaxGroupTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage)] + public void SerializationRoundtrip_Works(NewPlanMaxGroupTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMaxGroupTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanMinimumCompositePriceTest.cs b/src/Orb.Tests/Models/NewPlanMinimumCompositePriceTest.cs new file mode 100644 index 00000000..d2b72405 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanMinimumCompositePriceTest.cs @@ -0,0 +1,801 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanMinimumCompositePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanMinimumCompositePriceCadence.Annual; + string expectedItemID = "item_id"; + NewPlanMinimumCompositePriceMinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + ApiEnum expectedModelType = + NewPlanMinimumCompositePriceModelType.Minimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMinimumCompositePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMinimumConfig, model.MinimumConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanMinimumCompositePriceCadence.Annual; + string expectedItemID = "item_id"; + NewPlanMinimumCompositePriceMinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + ApiEnum expectedModelType = + NewPlanMinimumCompositePriceModelType.Minimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanMinimumCompositePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMinimumConfig, deserialized.MinimumConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanMinimumCompositePrice + { + Cadence = NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanMinimumCompositePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanMinimumCompositePriceCadence.Annual)] + [InlineData(NewPlanMinimumCompositePriceCadence.SemiAnnual)] + [InlineData(NewPlanMinimumCompositePriceCadence.Monthly)] + [InlineData(NewPlanMinimumCompositePriceCadence.Quarterly)] + [InlineData(NewPlanMinimumCompositePriceCadence.OneTime)] + [InlineData(NewPlanMinimumCompositePriceCadence.Custom)] + public void Validation_Works(NewPlanMinimumCompositePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMinimumCompositePriceCadence.Annual)] + [InlineData(NewPlanMinimumCompositePriceCadence.SemiAnnual)] + [InlineData(NewPlanMinimumCompositePriceCadence.Monthly)] + [InlineData(NewPlanMinimumCompositePriceCadence.Quarterly)] + [InlineData(NewPlanMinimumCompositePriceCadence.OneTime)] + [InlineData(NewPlanMinimumCompositePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanMinimumCompositePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMinimumCompositePriceMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedProrated, model.Prorated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedProrated, deserialized.Prorated); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanMinimumCompositePriceMinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + model.Validate(); + } +} + +public class NewPlanMinimumCompositePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanMinimumCompositePriceModelType.Minimum)] + public void Validation_Works(NewPlanMinimumCompositePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanMinimumCompositePriceModelType.Minimum)] + public void SerializationRoundtrip_Works(NewPlanMinimumCompositePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanMinimumCompositePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanMinimumCompositePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanMinimumCompositePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanMinimumCompositePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanMinimumCompositePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanPackagePriceTest.cs b/src/Orb.Tests/Models/NewPlanPackagePriceTest.cs new file mode 100644 index 00000000..98339a54 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanPackagePriceTest.cs @@ -0,0 +1,675 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanPackagePriceModelType.Package; + string expectedName = "Annual fee"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageConfig, model.PackageConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanPackagePriceModelType.Package; + string expectedName = "Annual fee"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageConfig, deserialized.PackageConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanPackagePrice + { + Cadence = NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanPackagePriceCadence.Annual)] + [InlineData(NewPlanPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanPackagePriceCadence.Monthly)] + [InlineData(NewPlanPackagePriceCadence.Quarterly)] + [InlineData(NewPlanPackagePriceCadence.OneTime)] + [InlineData(NewPlanPackagePriceCadence.Custom)] + public void Validation_Works(NewPlanPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanPackagePriceCadence.Annual)] + [InlineData(NewPlanPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanPackagePriceCadence.Monthly)] + [InlineData(NewPlanPackagePriceCadence.Quarterly)] + [InlineData(NewPlanPackagePriceCadence.OneTime)] + [InlineData(NewPlanPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanPackagePriceModelType.Package)] + public void Validation_Works(NewPlanPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanPackagePriceModelType.Package)] + public void SerializationRoundtrip_Works(NewPlanPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanPackageWithAllocationPriceTest.cs b/src/Orb.Tests/Models/NewPlanPackageWithAllocationPriceTest.cs new file mode 100644 index 00000000..6ee17fda --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanPackageWithAllocationPriceTest.cs @@ -0,0 +1,807 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanPackageWithAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanPackageWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation; + string expectedName = "Annual fee"; + NewPlanPackageWithAllocationPricePackageWithAllocationConfig expectedPackageWithAllocationConfig = + new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanPackageWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageWithAllocationConfig, model.PackageWithAllocationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanPackageWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation; + string expectedName = "Annual fee"; + NewPlanPackageWithAllocationPricePackageWithAllocationConfig expectedPackageWithAllocationConfig = + new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanPackageWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageWithAllocationConfig, deserialized.PackageWithAllocationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanPackageWithAllocationPrice + { + Cadence = NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanPackageWithAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Annual)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Monthly)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Quarterly)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.OneTime)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Custom)] + public void Validation_Works(NewPlanPackageWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Annual)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Monthly)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Quarterly)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.OneTime)] + [InlineData(NewPlanPackageWithAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanPackageWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanPackageWithAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation)] + public void Validation_Works(NewPlanPackageWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation)] + public void SerializationRoundtrip_Works(NewPlanPackageWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanPackageWithAllocationPricePackageWithAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanPackageWithAllocationPricePackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedPackageAmount, model.PackageAmount); + Assert.Equal(expectedPackageSize, model.PackageSize); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanPackageWithAllocationPricePackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanPackageWithAllocationPricePackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedPackageAmount, deserialized.PackageAmount); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanPackageWithAllocationPricePackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + model.Validate(); + } +} + +public class NewPlanPackageWithAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanPackageWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanPackageWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanPackageWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanPackageWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanScalableMatrixWithTieredPricingPriceTest.cs b/src/Orb.Tests/Models/NewPlanScalableMatrixWithTieredPricingPriceTest.cs new file mode 100644 index 00000000..6fec5f08 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanScalableMatrixWithTieredPricingPriceTest.cs @@ -0,0 +1,1394 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanScalableMatrixWithTieredPricingPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing; + string expectedName = "Annual fee"; + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + model.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing; + string expectedName = "Annual fee"; + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + deserialized.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanScalableMatrixWithTieredPricingPrice + { + Cadence = NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithTieredPricingPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.SemiAnnual)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Monthly)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Quarterly)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.OneTime)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Custom)] + public void Validation_Works(NewPlanScalableMatrixWithTieredPricingPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.SemiAnnual)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Monthly)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Quarterly)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.OneTime)] + [InlineData(NewPlanScalableMatrixWithTieredPricingPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewPlanScalableMatrixWithTieredPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanScalableMatrixWithTieredPricingPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing + )] + public void Validation_Works(NewPlanScalableMatrixWithTieredPricingPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing + )] + public void SerializationRoundtrip_Works( + NewPlanScalableMatrixWithTieredPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactorTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTierTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanScalableMatrixWithUnitPricingPriceTest.cs b/src/Orb.Tests/Models/NewPlanScalableMatrixWithUnitPricingPriceTest.cs new file mode 100644 index 00000000..07fdd28f --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanScalableMatrixWithUnitPricingPriceTest.cs @@ -0,0 +1,1241 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanScalableMatrixWithUnitPricingPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing; + string expectedName = "Annual fee"; + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + model.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing; + string expectedName = "Annual fee"; + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + deserialized.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPrice + { + Cadence = NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithUnitPricingPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.SemiAnnual)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Monthly)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Quarterly)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.OneTime)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Custom)] + public void Validation_Works(NewPlanScalableMatrixWithUnitPricingPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.SemiAnnual)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Monthly)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Quarterly)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.OneTime)] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewPlanScalableMatrixWithUnitPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanScalableMatrixWithUnitPricingPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing)] + public void Validation_Works(NewPlanScalableMatrixWithUnitPricingPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing)] + public void SerializationRoundtrip_Works( + NewPlanScalableMatrixWithUnitPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, model.UnitPrice); + Assert.Equal(expectedProrate, model.Prorate); + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, deserialized.UnitPrice); + Assert.Equal(expectedProrate, deserialized.Prorate); + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactorTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanThresholdTotalAmountPriceTest.cs b/src/Orb.Tests/Models/NewPlanThresholdTotalAmountPriceTest.cs new file mode 100644 index 00000000..fa690990 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanThresholdTotalAmountPriceTest.cs @@ -0,0 +1,1000 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanThresholdTotalAmountPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanThresholdTotalAmountPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount; + string expectedName = "Annual fee"; + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = + new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanThresholdTotalAmountPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedThresholdTotalAmountConfig, model.ThresholdTotalAmountConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanThresholdTotalAmountPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount; + string expectedName = "Annual fee"; + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = + new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanThresholdTotalAmountPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedThresholdTotalAmountConfig, deserialized.ThresholdTotalAmountConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanThresholdTotalAmountPrice + { + Cadence = NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanThresholdTotalAmountPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Annual)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.SemiAnnual)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Monthly)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Quarterly)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.OneTime)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Custom)] + public void Validation_Works(NewPlanThresholdTotalAmountPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Annual)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.SemiAnnual)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Monthly)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Quarterly)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.OneTime)] + [InlineData(NewPlanThresholdTotalAmountPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanThresholdTotalAmountPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanThresholdTotalAmountPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount)] + public void Validation_Works(NewPlanThresholdTotalAmountPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount)] + public void SerializationRoundtrip_Works(NewPlanThresholdTotalAmountPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, model.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], model.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, deserialized.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], deserialized.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + model.Validate(); + } +} + +public class NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTableTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedTotalAmount, model.TotalAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedTotalAmount, deserialized.TotalAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + model.Validate(); + } +} + +public class NewPlanThresholdTotalAmountPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanTieredPackagePriceTest.cs b/src/Orb.Tests/Models/NewPlanTieredPackagePriceTest.cs new file mode 100644 index 00000000..75f50910 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanTieredPackagePriceTest.cs @@ -0,0 +1,913 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredPackagePriceModelType.TieredPackage; + string expectedName = "Annual fee"; + NewPlanTieredPackagePriceTieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredPackageConfig, model.TieredPackageConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredPackagePriceModelType.TieredPackage; + string expectedName = "Annual fee"; + NewPlanTieredPackagePriceTieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredPackageConfig, deserialized.TieredPackageConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanTieredPackagePrice + { + Cadence = NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredPackagePriceCadence.Annual)] + [InlineData(NewPlanTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredPackagePriceCadence.Monthly)] + [InlineData(NewPlanTieredPackagePriceCadence.Quarterly)] + [InlineData(NewPlanTieredPackagePriceCadence.OneTime)] + [InlineData(NewPlanTieredPackagePriceCadence.Custom)] + public void Validation_Works(NewPlanTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredPackagePriceCadence.Annual)] + [InlineData(NewPlanTieredPackagePriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredPackagePriceCadence.Monthly)] + [InlineData(NewPlanTieredPackagePriceCadence.Quarterly)] + [InlineData(NewPlanTieredPackagePriceCadence.OneTime)] + [InlineData(NewPlanTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredPackagePriceModelType.TieredPackage)] + public void Validation_Works(NewPlanTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredPackagePriceModelType.TieredPackage)] + public void SerializationRoundtrip_Works(NewPlanTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredPackagePriceTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanTieredPackagePriceTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPackagePriceTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewPlanTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanTieredPackageWithMinimumPriceTest.cs b/src/Orb.Tests/Models/NewPlanTieredPackageWithMinimumPriceTest.cs new file mode 100644 index 00000000..49e1cd60 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanTieredPackageWithMinimumPriceTest.cs @@ -0,0 +1,1106 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanTieredPackageWithMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanTieredPackageWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum; + string expectedName = "Annual fee"; + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = + new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredPackageWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredPackageWithMinimumConfig, model.TieredPackageWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanTieredPackageWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum; + string expectedName = "Annual fee"; + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = + new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredPackageWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedTieredPackageWithMinimumConfig, + deserialized.TieredPackageWithMinimumConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanTieredPackageWithMinimumPrice + { + Cadence = NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanTieredPackageWithMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Annual)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Monthly)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.OneTime)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Custom)] + public void Validation_Works(NewPlanTieredPackageWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Annual)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Monthly)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.OneTime)] + [InlineData(NewPlanTieredPackageWithMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanTieredPackageWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredPackageWithMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum)] + public void Validation_Works(NewPlanTieredPackageWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum)] + public void SerializationRoundtrip_Works(NewPlanTieredPackageWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + model.Validate(); + } +} + +public class NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewPlanTieredPackageWithMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanTieredPriceTest.cs b/src/Orb.Tests/Models/NewPlanTieredPriceTest.cs new file mode 100644 index 00000000..8ff7a929 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanTieredPriceTest.cs @@ -0,0 +1,789 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanTieredPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanTieredPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredPriceModelType.Tiered; + string expectedName = "Annual fee"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredConfig, model.TieredConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanTieredPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredPriceModelType.Tiered; + string expectedName = "Annual fee"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredConfig, deserialized.TieredConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanTieredPrice + { + Cadence = NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanTieredPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredPriceCadence.Annual)] + [InlineData(NewPlanTieredPriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredPriceCadence.Monthly)] + [InlineData(NewPlanTieredPriceCadence.Quarterly)] + [InlineData(NewPlanTieredPriceCadence.OneTime)] + [InlineData(NewPlanTieredPriceCadence.Custom)] + public void Validation_Works(NewPlanTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredPriceCadence.Annual)] + [InlineData(NewPlanTieredPriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredPriceCadence.Monthly)] + [InlineData(NewPlanTieredPriceCadence.Quarterly)] + [InlineData(NewPlanTieredPriceCadence.OneTime)] + [InlineData(NewPlanTieredPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredPriceModelType.Tiered)] + public void Validation_Works(NewPlanTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredPriceModelType.Tiered)] + public void SerializationRoundtrip_Works(NewPlanTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanTieredWithMinimumPriceTest.cs b/src/Orb.Tests/Models/NewPlanTieredWithMinimumPriceTest.cs new file mode 100644 index 00000000..ca8ae1b3 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanTieredWithMinimumPriceTest.cs @@ -0,0 +1,1225 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanTieredWithMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanTieredWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum; + string expectedName = "Annual fee"; + NewPlanTieredWithMinimumPriceTieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithMinimumConfig, model.TieredWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanTieredWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum; + string expectedName = "Annual fee"; + NewPlanTieredWithMinimumPriceTieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanTieredWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithMinimumConfig, deserialized.TieredWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanTieredWithMinimumPrice + { + Cadence = NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanTieredWithMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Annual)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Monthly)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.OneTime)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Custom)] + public void Validation_Works(NewPlanTieredWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Annual)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.SemiAnnual)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Monthly)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Quarterly)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.OneTime)] + [InlineData(NewPlanTieredWithMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanTieredWithMinimumPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredWithMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum)] + public void Validation_Works(NewPlanTieredWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum)] + public void SerializationRoundtrip_Works(NewPlanTieredWithMinimumPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, model.HideZeroAmountTiers); + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, deserialized.HideZeroAmountTiers); + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + model.Validate(); + } +} + +public class NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanTieredWithMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanTieredWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanTieredWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanTieredWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanTieredWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanUnitPriceTest.cs b/src/Orb.Tests/Models/NewPlanUnitPriceTest.cs new file mode 100644 index 00000000..dd10bfa1 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanUnitPriceTest.cs @@ -0,0 +1,667 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanUnitPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = NewPlanUnitPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanUnitPriceModelType.Unit; + string expectedName = "Annual fee"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanUnitPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitConfig, model.UnitConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = NewPlanUnitPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanUnitPriceModelType.Unit; + string expectedName = "Annual fee"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanUnitPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitConfig, deserialized.UnitConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanUnitPrice + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanUnitPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanUnitPriceCadence.Annual)] + [InlineData(NewPlanUnitPriceCadence.SemiAnnual)] + [InlineData(NewPlanUnitPriceCadence.Monthly)] + [InlineData(NewPlanUnitPriceCadence.Quarterly)] + [InlineData(NewPlanUnitPriceCadence.OneTime)] + [InlineData(NewPlanUnitPriceCadence.Custom)] + public void Validation_Works(NewPlanUnitPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanUnitPriceCadence.Annual)] + [InlineData(NewPlanUnitPriceCadence.SemiAnnual)] + [InlineData(NewPlanUnitPriceCadence.Monthly)] + [InlineData(NewPlanUnitPriceCadence.Quarterly)] + [InlineData(NewPlanUnitPriceCadence.OneTime)] + [InlineData(NewPlanUnitPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanUnitPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanUnitPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanUnitPriceModelType.Unit)] + public void Validation_Works(NewPlanUnitPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanUnitPriceModelType.Unit)] + public void SerializationRoundtrip_Works(NewPlanUnitPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanUnitPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanUnitPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanUnitPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanUnitPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanUnitPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanUnitWithPercentPriceTest.cs b/src/Orb.Tests/Models/NewPlanUnitWithPercentPriceTest.cs new file mode 100644 index 00000000..2161be02 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanUnitWithPercentPriceTest.cs @@ -0,0 +1,743 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanUnitWithPercentPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanUnitWithPercentPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanUnitWithPercentPriceModelType.UnitWithPercent; + string expectedName = "Annual fee"; + NewPlanUnitWithPercentPriceUnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanUnitWithPercentPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitWithPercentConfig, model.UnitWithPercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanUnitWithPercentPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanUnitWithPercentPriceModelType.UnitWithPercent; + string expectedName = "Annual fee"; + NewPlanUnitWithPercentPriceUnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanUnitWithPercentPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitWithPercentConfig, deserialized.UnitWithPercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanUnitWithPercentPrice + { + Cadence = NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanUnitWithPercentPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanUnitWithPercentPriceCadence.Annual)] + [InlineData(NewPlanUnitWithPercentPriceCadence.SemiAnnual)] + [InlineData(NewPlanUnitWithPercentPriceCadence.Monthly)] + [InlineData(NewPlanUnitWithPercentPriceCadence.Quarterly)] + [InlineData(NewPlanUnitWithPercentPriceCadence.OneTime)] + [InlineData(NewPlanUnitWithPercentPriceCadence.Custom)] + public void Validation_Works(NewPlanUnitWithPercentPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanUnitWithPercentPriceCadence.Annual)] + [InlineData(NewPlanUnitWithPercentPriceCadence.SemiAnnual)] + [InlineData(NewPlanUnitWithPercentPriceCadence.Monthly)] + [InlineData(NewPlanUnitWithPercentPriceCadence.Quarterly)] + [InlineData(NewPlanUnitWithPercentPriceCadence.OneTime)] + [InlineData(NewPlanUnitWithPercentPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanUnitWithPercentPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanUnitWithPercentPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanUnitWithPercentPriceModelType.UnitWithPercent)] + public void Validation_Works(NewPlanUnitWithPercentPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanUnitWithPercentPriceModelType.UnitWithPercent)] + public void SerializationRoundtrip_Works(NewPlanUnitWithPercentPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanUnitWithPercentPriceUnitWithPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanUnitWithPercentPriceUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, model.Percent); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanUnitWithPercentPriceUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanUnitWithPercentPriceUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, deserialized.Percent); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanUnitWithPercentPriceUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanUnitWithPercentPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanUnitWithPercentPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanUnitWithPercentPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanUnitWithPercentPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanUnitWithPercentPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewPlanUnitWithProrationPriceTest.cs b/src/Orb.Tests/Models/NewPlanUnitWithProrationPriceTest.cs new file mode 100644 index 00000000..2784b680 --- /dev/null +++ b/src/Orb.Tests/Models/NewPlanUnitWithProrationPriceTest.cs @@ -0,0 +1,737 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewPlanUnitWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewPlanUnitWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanUnitWithProrationPriceModelType.UnitWithProration; + string expectedName = "Annual fee"; + NewPlanUnitWithProrationPriceUnitWithProrationConfig expectedUnitWithProrationConfig = new( + "unit_amount" + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanUnitWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitWithProrationConfig, model.UnitWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewPlanUnitWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewPlanUnitWithProrationPriceModelType.UnitWithProration; + string expectedName = "Annual fee"; + NewPlanUnitWithProrationPriceUnitWithProrationConfig expectedUnitWithProrationConfig = new( + "unit_amount" + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewPlanUnitWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitWithProrationConfig, deserialized.UnitWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewPlanUnitWithProrationPrice + { + Cadence = NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewPlanUnitWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewPlanUnitWithProrationPriceCadence.Annual)] + [InlineData(NewPlanUnitWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewPlanUnitWithProrationPriceCadence.Monthly)] + [InlineData(NewPlanUnitWithProrationPriceCadence.Quarterly)] + [InlineData(NewPlanUnitWithProrationPriceCadence.OneTime)] + [InlineData(NewPlanUnitWithProrationPriceCadence.Custom)] + public void Validation_Works(NewPlanUnitWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanUnitWithProrationPriceCadence.Annual)] + [InlineData(NewPlanUnitWithProrationPriceCadence.SemiAnnual)] + [InlineData(NewPlanUnitWithProrationPriceCadence.Monthly)] + [InlineData(NewPlanUnitWithProrationPriceCadence.Quarterly)] + [InlineData(NewPlanUnitWithProrationPriceCadence.OneTime)] + [InlineData(NewPlanUnitWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewPlanUnitWithProrationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanUnitWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewPlanUnitWithProrationPriceModelType.UnitWithProration)] + public void Validation_Works(NewPlanUnitWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewPlanUnitWithProrationPriceModelType.UnitWithProration)] + public void SerializationRoundtrip_Works(NewPlanUnitWithProrationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewPlanUnitWithProrationPriceUnitWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewPlanUnitWithProrationPriceUnitWithProrationConfig + { + UnitAmount = "unit_amount", + }; + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewPlanUnitWithProrationPriceUnitWithProrationConfig + { + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewPlanUnitWithProrationPriceUnitWithProrationConfig + { + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new NewPlanUnitWithProrationPriceUnitWithProrationConfig + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewPlanUnitWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewPlanUnitWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewPlanUnitWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewPlanUnitWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewPlanUnitWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/NewUsageDiscountTest.cs b/src/Orb.Tests/Models/NewUsageDiscountTest.cs new file mode 100644 index 00000000..202f7e2d --- /dev/null +++ b/src/Orb.Tests/Models/NewUsageDiscountTest.cs @@ -0,0 +1,793 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class NewUsageDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + }; + + ApiEnum expectedAdjustmentType = + NewUsageDiscountAdjustmentType.UsageDiscount; + double expectedUsageDiscount = 0; + ApiEnum expectedAppliesToAll = + NewUsageDiscountAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = + NewUsageDiscountPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedUsageDiscount, model.UsageDiscount); + Assert.Equal(expectedAppliesToAll, model.AppliesToAll); + Assert.NotNull(model.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, model.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], model.AppliesToItemIDs[i]); + } + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, model.Currency); + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPriceType, model.PriceType); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedAdjustmentType = + NewUsageDiscountAdjustmentType.UsageDiscount; + double expectedUsageDiscount = 0; + ApiEnum expectedAppliesToAll = + NewUsageDiscountAppliesToAll.True; + List expectedAppliesToItemIDs = ["item_1", "item_2"]; + List expectedAppliesToPriceIDs = ["price_1", "price_2"]; + string expectedCurrency = "currency"; + List expectedFilters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + ApiEnum expectedPriceType = + NewUsageDiscountPriceType.Usage; + + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedUsageDiscount, deserialized.UsageDiscount); + Assert.Equal(expectedAppliesToAll, deserialized.AppliesToAll); + Assert.NotNull(deserialized.AppliesToItemIDs); + Assert.Equal(expectedAppliesToItemIDs.Count, deserialized.AppliesToItemIDs.Count); + for (int i = 0; i < expectedAppliesToItemIDs.Count; i++) + { + Assert.Equal(expectedAppliesToItemIDs[i], deserialized.AppliesToItemIDs[i]); + } + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPriceType, deserialized.PriceType); + } + + [Fact] + public void Validation_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewUsageDiscountPriceType.Usage, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewUsageDiscountPriceType.Usage, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewUsageDiscountPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + Assert.Null(model.IsInvoiceLevel); + Assert.False(model.RawData.ContainsKey("is_invoice_level")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + PriceType = NewUsageDiscountPriceType.Usage, + + // Null should be interpreted as omitted for these properties + IsInvoiceLevel = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + IsInvoiceLevel = true, + }; + + Assert.Null(model.AppliesToAll); + Assert.False(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.False(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.False(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + IsInvoiceLevel = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + Assert.Null(model.AppliesToAll); + Assert.True(model.RawData.ContainsKey("applies_to_all")); + Assert.Null(model.AppliesToItemIDs); + Assert.True(model.RawData.ContainsKey("applies_to_item_ids")); + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.PriceType); + Assert.True(model.RawData.ContainsKey("price_type")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewUsageDiscount + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + IsInvoiceLevel = true, + + AppliesToAll = null, + AppliesToItemIDs = null, + AppliesToPriceIDs = null, + Currency = null, + Filters = null, + PriceType = null, + }; + + model.Validate(); + } +} + +public class NewUsageDiscountAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(NewUsageDiscountAdjustmentType.UsageDiscount)] + public void Validation_Works(NewUsageDiscountAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewUsageDiscountAdjustmentType.UsageDiscount)] + public void SerializationRoundtrip_Works(NewUsageDiscountAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewUsageDiscountAppliesToAllTest : TestBase +{ + [Theory] + [InlineData(NewUsageDiscountAppliesToAll.True)] + public void Validation_Works(NewUsageDiscountAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewUsageDiscountAppliesToAll.True)] + public void SerializationRoundtrip_Works(NewUsageDiscountAppliesToAll rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewUsageDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewUsageDiscountFilter + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + NewUsageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + NewUsageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewUsageDiscountFilter + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewUsageDiscountFilter + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + NewUsageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + NewUsageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new NewUsageDiscountFilter + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class NewUsageDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(NewUsageDiscountFilterField.PriceID)] + [InlineData(NewUsageDiscountFilterField.ItemID)] + [InlineData(NewUsageDiscountFilterField.PriceType)] + [InlineData(NewUsageDiscountFilterField.Currency)] + [InlineData(NewUsageDiscountFilterField.PricingUnitID)] + public void Validation_Works(NewUsageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewUsageDiscountFilterField.PriceID)] + [InlineData(NewUsageDiscountFilterField.ItemID)] + [InlineData(NewUsageDiscountFilterField.PriceType)] + [InlineData(NewUsageDiscountFilterField.Currency)] + [InlineData(NewUsageDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(NewUsageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewUsageDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(NewUsageDiscountFilterOperator.Includes)] + [InlineData(NewUsageDiscountFilterOperator.Excludes)] + public void Validation_Works(NewUsageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewUsageDiscountFilterOperator.Includes)] + [InlineData(NewUsageDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(NewUsageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewUsageDiscountPriceTypeTest : TestBase +{ + [Theory] + [InlineData(NewUsageDiscountPriceType.Usage)] + [InlineData(NewUsageDiscountPriceType.FixedInAdvance)] + [InlineData(NewUsageDiscountPriceType.FixedInArrears)] + [InlineData(NewUsageDiscountPriceType.Fixed)] + [InlineData(NewUsageDiscountPriceType.InArrears)] + public void Validation_Works(NewUsageDiscountPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewUsageDiscountPriceType.Usage)] + [InlineData(NewUsageDiscountPriceType.FixedInAdvance)] + [InlineData(NewUsageDiscountPriceType.FixedInArrears)] + [InlineData(NewUsageDiscountPriceType.Fixed)] + [InlineData(NewUsageDiscountPriceType.InArrears)] + public void SerializationRoundtrip_Works(NewUsageDiscountPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/OtherSubLineItemTest.cs b/src/Orb.Tests/Models/OtherSubLineItemTest.cs new file mode 100644 index 00000000..abc0783d --- /dev/null +++ b/src/Orb.Tests/Models/OtherSubLineItemTest.cs @@ -0,0 +1,152 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class OtherSubLineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new OtherSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + }; + + string expectedAmount = "9.00"; + SubLineItemGrouping expectedGrouping = new() { Key = "region", Value = "west" }; + string expectedName = "Tier One"; + double expectedQuantity = 5; + ApiEnum expectedType = OtherSubLineItemType.Null; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new OtherSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new OtherSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "9.00"; + SubLineItemGrouping expectedGrouping = new() { Key = "region", Value = "west" }; + string expectedName = "Tier One"; + double expectedQuantity = 5; + ApiEnum expectedType = OtherSubLineItemType.Null; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new OtherSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + Type = OtherSubLineItemType.Null, + }; + + model.Validate(); + } +} + +public class OtherSubLineItemTypeTest : TestBase +{ + [Theory] + [InlineData(OtherSubLineItemType.Null)] + public void Validation_Works(OtherSubLineItemType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(OtherSubLineItemType.Null)] + public void SerializationRoundtrip_Works(OtherSubLineItemType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PackageConfigTest.cs b/src/Orb.Tests/Models/PackageConfigTest.cs new file mode 100644 index 00000000..d005c3ac --- /dev/null +++ b/src/Orb.Tests/Models/PackageConfigTest.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PackageConfig { PackageAmount = "package_amount", PackageSize = 1 }; + + string expectedPackageAmount = "package_amount"; + long expectedPackageSize = 1; + + Assert.Equal(expectedPackageAmount, model.PackageAmount); + Assert.Equal(expectedPackageSize, model.PackageSize); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PackageConfig { PackageAmount = "package_amount", PackageSize = 1 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PackageConfig { PackageAmount = "package_amount", PackageSize = 1 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPackageAmount = "package_amount"; + long expectedPackageSize = 1; + + Assert.Equal(expectedPackageAmount, deserialized.PackageAmount); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + } + + [Fact] + public void Validation_Works() + { + var model = new PackageConfig { PackageAmount = "package_amount", PackageSize = 1 }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/PaginationMetadataTest.cs b/src/Orb.Tests/Models/PaginationMetadataTest.cs new file mode 100644 index 00000000..ff345b8e --- /dev/null +++ b/src/Orb.Tests/Models/PaginationMetadataTest.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PaginationMetadataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PaginationMetadata { HasMore = true, NextCursor = "next_cursor" }; + + bool expectedHasMore = true; + string expectedNextCursor = "next_cursor"; + + Assert.Equal(expectedHasMore, model.HasMore); + Assert.Equal(expectedNextCursor, model.NextCursor); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PaginationMetadata { HasMore = true, NextCursor = "next_cursor" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PaginationMetadata { HasMore = true, NextCursor = "next_cursor" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + bool expectedHasMore = true; + string expectedNextCursor = "next_cursor"; + + Assert.Equal(expectedHasMore, deserialized.HasMore); + Assert.Equal(expectedNextCursor, deserialized.NextCursor); + } + + [Fact] + public void Validation_Works() + { + var model = new PaginationMetadata { HasMore = true, NextCursor = "next_cursor" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/PerPriceCostTest.cs b/src/Orb.Tests/Models/PerPriceCostTest.cs new file mode 100644 index 00000000..75a283d7 --- /dev/null +++ b/src/Orb.Tests/Models/PerPriceCostTest.cs @@ -0,0 +1,1230 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PerPriceCostTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }; + + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + string expectedPriceID = "price_id"; + string expectedSubtotal = "subtotal"; + string expectedTotal = "total"; + double expectedQuantity = 0; + + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedQuantity, model.Quantity); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + string expectedPriceID = "price_id"; + string expectedSubtotal = "subtotal"; + string expectedTotal = "total"; + double expectedQuantity = 0; + + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedQuantity, deserialized.Quantity); + } + + [Fact] + public void Validation_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + }; + + Assert.Null(model.Quantity); + Assert.False(model.RawData.ContainsKey("quantity")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + + Quantity = null, + }; + + Assert.Null(model.Quantity); + Assert.True(model.RawData.ContainsKey("quantity")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PerPriceCost + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + + Quantity = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/PercentageDiscountIntervalTest.cs b/src/Orb.Tests/Models/PercentageDiscountIntervalTest.cs new file mode 100644 index 00000000..14b78ec3 --- /dev/null +++ b/src/Orb.Tests/Models/PercentageDiscountIntervalTest.cs @@ -0,0 +1,451 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PercentageDiscountIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + List expectedAppliesToPriceIntervalIDs = ["string"]; + ApiEnum expectedDiscountType = + PercentageDiscountIntervalDiscountType.Percentage; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedPercentageDiscount = 0.15; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + model.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIntervalIDs[i], model.AppliesToPriceIntervalIDs[i]); + } + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAppliesToPriceIntervalIDs = ["string"]; + ApiEnum expectedDiscountType = + PercentageDiscountIntervalDiscountType.Percentage; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedPercentageDiscount = 0.15; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + deserialized.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal( + expectedAppliesToPriceIntervalIDs[i], + deserialized.AppliesToPriceIntervalIDs[i] + ); + } + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class PercentageDiscountIntervalDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(PercentageDiscountIntervalDiscountType.Percentage)] + public void Validation_Works(PercentageDiscountIntervalDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentageDiscountIntervalDiscountType.Percentage)] + public void SerializationRoundtrip_Works(PercentageDiscountIntervalDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentageDiscountIntervalFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentageDiscountIntervalFilter + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PercentageDiscountIntervalFilterField.PriceID; + ApiEnum expectedOperator = + PercentageDiscountIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentageDiscountIntervalFilter + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentageDiscountIntervalFilter + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PercentageDiscountIntervalFilterField.PriceID; + ApiEnum expectedOperator = + PercentageDiscountIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PercentageDiscountIntervalFilter + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PercentageDiscountIntervalFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PercentageDiscountIntervalFilterField.PriceID)] + [InlineData(PercentageDiscountIntervalFilterField.ItemID)] + [InlineData(PercentageDiscountIntervalFilterField.PriceType)] + [InlineData(PercentageDiscountIntervalFilterField.Currency)] + [InlineData(PercentageDiscountIntervalFilterField.PricingUnitID)] + public void Validation_Works(PercentageDiscountIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentageDiscountIntervalFilterField.PriceID)] + [InlineData(PercentageDiscountIntervalFilterField.ItemID)] + [InlineData(PercentageDiscountIntervalFilterField.PriceType)] + [InlineData(PercentageDiscountIntervalFilterField.Currency)] + [InlineData(PercentageDiscountIntervalFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PercentageDiscountIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentageDiscountIntervalFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PercentageDiscountIntervalFilterOperator.Includes)] + [InlineData(PercentageDiscountIntervalFilterOperator.Excludes)] + public void Validation_Works(PercentageDiscountIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentageDiscountIntervalFilterOperator.Includes)] + [InlineData(PercentageDiscountIntervalFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PercentageDiscountIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PercentageDiscountTest.cs b/src/Orb.Tests/Models/PercentageDiscountTest.cs new file mode 100644 index 00000000..4ae1151c --- /dev/null +++ b/src/Orb.Tests/Models/PercentageDiscountTest.cs @@ -0,0 +1,491 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PercentageDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + ApiEnum expectedDiscountType = + PercentageDiscountDiscountType.Percentage; + double expectedPercentageDiscountValue = 0.15; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedPercentageDiscountValue, model.PercentageDiscountValue); + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedReason, model.Reason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedDiscountType = + PercentageDiscountDiscountType.Percentage; + double expectedPercentageDiscountValue = 0.15; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedPercentageDiscountValue, deserialized.PercentageDiscountValue); + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedReason, deserialized.Reason); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PercentageDiscount + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + }; + + model.Validate(); + } +} + +public class PercentageDiscountDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(PercentageDiscountDiscountType.Percentage)] + public void Validation_Works(PercentageDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentageDiscountDiscountType.Percentage)] + public void SerializationRoundtrip_Works(PercentageDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentageDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentageDiscountFilter + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PercentageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + PercentageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentageDiscountFilter + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentageDiscountFilter + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PercentageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + PercentageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PercentageDiscountFilter + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PercentageDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PercentageDiscountFilterField.PriceID)] + [InlineData(PercentageDiscountFilterField.ItemID)] + [InlineData(PercentageDiscountFilterField.PriceType)] + [InlineData(PercentageDiscountFilterField.Currency)] + [InlineData(PercentageDiscountFilterField.PricingUnitID)] + public void Validation_Works(PercentageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentageDiscountFilterField.PriceID)] + [InlineData(PercentageDiscountFilterField.ItemID)] + [InlineData(PercentageDiscountFilterField.PriceType)] + [InlineData(PercentageDiscountFilterField.Currency)] + [InlineData(PercentageDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PercentageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentageDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PercentageDiscountFilterOperator.Includes)] + [InlineData(PercentageDiscountFilterOperator.Excludes)] + public void Validation_Works(PercentageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentageDiscountFilterOperator.Includes)] + [InlineData(PercentageDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PercentageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PlanPhaseAmountDiscountAdjustmentTest.cs b/src/Orb.Tests/Models/PlanPhaseAmountDiscountAdjustmentTest.cs new file mode 100644 index 00000000..0eda77e9 --- /dev/null +++ b/src/Orb.Tests/Models/PlanPhaseAmountDiscountAdjustmentTest.cs @@ -0,0 +1,473 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PlanPhaseAmountDiscountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount; + string expectedAmountDiscount = "amount_discount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount; + string expectedAmountDiscount = "amount_discount"; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseAmountDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class PlanPhaseAmountDiscountAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount)] + public void Validation_Works(PlanPhaseAmountDiscountAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount)] + public void SerializationRoundtrip_Works( + PlanPhaseAmountDiscountAdjustmentAdjustmentType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseAmountDiscountAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseAmountDiscountAdjustmentFilter + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PlanPhaseAmountDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseAmountDiscountAdjustmentFilter + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseAmountDiscountAdjustmentFilter + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PlanPhaseAmountDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseAmountDiscountAdjustmentFilter + { + Field = PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PlanPhaseAmountDiscountAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(PlanPhaseAmountDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PlanPhaseAmountDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseAmountDiscountAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterOperator.Excludes)] + public void Validation_Works(PlanPhaseAmountDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseAmountDiscountAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + PlanPhaseAmountDiscountAdjustmentFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PlanPhaseMaximumAdjustmentTest.cs b/src/Orb.Tests/Models/PlanPhaseMaximumAdjustmentTest.cs new file mode 100644 index 00000000..f144a055 --- /dev/null +++ b/src/Orb.Tests/Models/PlanPhaseMaximumAdjustmentTest.cs @@ -0,0 +1,465 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PlanPhaseMaximumAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseMaximumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseMaximumAdjustmentAdjustmentType.Maximum; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedMaximumAmount = "maximum_amount"; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseMaximumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseMaximumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseMaximumAdjustmentAdjustmentType.Maximum; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedMaximumAmount = "maximum_amount"; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseMaximumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class PlanPhaseMaximumAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseMaximumAdjustmentAdjustmentType.Maximum)] + public void Validation_Works(PlanPhaseMaximumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseMaximumAdjustmentAdjustmentType.Maximum)] + public void SerializationRoundtrip_Works(PlanPhaseMaximumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseMaximumAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseMaximumAdjustmentFilter + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PlanPhaseMaximumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseMaximumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseMaximumAdjustmentFilter + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseMaximumAdjustmentFilter + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PlanPhaseMaximumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseMaximumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseMaximumAdjustmentFilter + { + Field = PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PlanPhaseMaximumAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(PlanPhaseMaximumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseMaximumAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PlanPhaseMaximumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseMaximumAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseMaximumAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseMaximumAdjustmentFilterOperator.Excludes)] + public void Validation_Works(PlanPhaseMaximumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseMaximumAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseMaximumAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PlanPhaseMaximumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PlanPhaseMinimumAdjustmentTest.cs b/src/Orb.Tests/Models/PlanPhaseMinimumAdjustmentTest.cs new file mode 100644 index 00000000..5932dcfb --- /dev/null +++ b/src/Orb.Tests/Models/PlanPhaseMinimumAdjustmentTest.cs @@ -0,0 +1,473 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PlanPhaseMinimumAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseMinimumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseMinimumAdjustmentAdjustmentType.Minimum; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedItemID = "item_id"; + string expectedMinimumAmount = "minimum_amount"; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseMinimumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseMinimumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseMinimumAdjustmentAdjustmentType.Minimum; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + string expectedItemID = "item_id"; + string expectedMinimumAmount = "minimum_amount"; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseMinimumAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class PlanPhaseMinimumAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseMinimumAdjustmentAdjustmentType.Minimum)] + public void Validation_Works(PlanPhaseMinimumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseMinimumAdjustmentAdjustmentType.Minimum)] + public void SerializationRoundtrip_Works(PlanPhaseMinimumAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseMinimumAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseMinimumAdjustmentFilter + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PlanPhaseMinimumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseMinimumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseMinimumAdjustmentFilter + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseMinimumAdjustmentFilter + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PlanPhaseMinimumAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseMinimumAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseMinimumAdjustmentFilter + { + Field = PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PlanPhaseMinimumAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(PlanPhaseMinimumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseMinimumAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PlanPhaseMinimumAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseMinimumAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseMinimumAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseMinimumAdjustmentFilterOperator.Excludes)] + public void Validation_Works(PlanPhaseMinimumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseMinimumAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseMinimumAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PlanPhaseMinimumAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PlanPhasePercentageDiscountAdjustmentTest.cs b/src/Orb.Tests/Models/PlanPhasePercentageDiscountAdjustmentTest.cs new file mode 100644 index 00000000..3bb8ea05 --- /dev/null +++ b/src/Orb.Tests/Models/PlanPhasePercentageDiscountAdjustmentTest.cs @@ -0,0 +1,483 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PlanPhasePercentageDiscountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhasePercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string expectedID = "id"; + ApiEnum< + string, + PlanPhasePercentageDiscountAdjustmentAdjustmentType + > expectedAdjustmentType = + PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + double expectedPercentageDiscount = 0; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhasePercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhasePercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum< + string, + PlanPhasePercentageDiscountAdjustmentAdjustmentType + > expectedAdjustmentType = + PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + double expectedPercentageDiscount = 0; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhasePercentageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class PlanPhasePercentageDiscountAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount)] + public void Validation_Works(PlanPhasePercentageDiscountAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount)] + public void SerializationRoundtrip_Works( + PlanPhasePercentageDiscountAdjustmentAdjustmentType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhasePercentageDiscountAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhasePercentageDiscountAdjustmentFilter + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PlanPhasePercentageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhasePercentageDiscountAdjustmentFilter + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhasePercentageDiscountAdjustmentFilter + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PlanPhasePercentageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhasePercentageDiscountAdjustmentFilter + { + Field = PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PlanPhasePercentageDiscountAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.PriceID)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.ItemID)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.PriceType)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.Currency)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(PlanPhasePercentageDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.PriceID)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.ItemID)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.PriceType)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.Currency)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + PlanPhasePercentageDiscountAdjustmentFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhasePercentageDiscountAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterOperator.Excludes)] + public void Validation_Works(PlanPhasePercentageDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhasePercentageDiscountAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + PlanPhasePercentageDiscountAdjustmentFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/PlanPhaseUsageDiscountAdjustmentTest.cs b/src/Orb.Tests/Models/PlanPhaseUsageDiscountAdjustmentTest.cs new file mode 100644 index 00000000..a638bf17 --- /dev/null +++ b/src/Orb.Tests/Models/PlanPhaseUsageDiscountAdjustmentTest.cs @@ -0,0 +1,471 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PlanPhaseUsageDiscountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + double expectedUsageDiscount = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustmentType, model.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, model.IsInvoiceLevel); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + Assert.Equal(expectedUsageDiscount, model.UsageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + ApiEnum expectedAdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount; + List expectedAppliesToPriceIDs = ["string"]; + List expectedFilters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ]; + bool expectedIsInvoiceLevel = true; + long expectedPlanPhaseOrder = 0; + string expectedReason = "reason"; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + double expectedUsageDiscount = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustmentType, deserialized.AdjustmentType); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedIsInvoiceLevel, deserialized.IsInvoiceLevel); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + Assert.Equal(expectedUsageDiscount, deserialized.UsageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseUsageDiscountAdjustment + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }; + + model.Validate(); + } +} + +public class PlanPhaseUsageDiscountAdjustmentAdjustmentTypeTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount)] + public void Validation_Works(PlanPhaseUsageDiscountAdjustmentAdjustmentType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount)] + public void SerializationRoundtrip_Works( + PlanPhaseUsageDiscountAdjustmentAdjustmentType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseUsageDiscountAdjustmentFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhaseUsageDiscountAdjustmentFilter + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PlanPhaseUsageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhaseUsageDiscountAdjustmentFilter + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhaseUsageDiscountAdjustmentFilter + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PlanPhaseUsageDiscountAdjustmentFilterField.PriceID; + ApiEnum expectedOperator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhaseUsageDiscountAdjustmentFilter + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PlanPhaseUsageDiscountAdjustmentFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.PricingUnitID)] + public void Validation_Works(PlanPhaseUsageDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.PriceID)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.ItemID)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.PriceType)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.Currency)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PlanPhaseUsageDiscountAdjustmentFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseUsageDiscountAdjustmentFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterOperator.Excludes)] + public void Validation_Works(PlanPhaseUsageDiscountAdjustmentFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes)] + [InlineData(PlanPhaseUsageDiscountAdjustmentFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + PlanPhaseUsageDiscountAdjustmentFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParamsTest.cs b/src/Orb.Tests/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParamsTest.cs new file mode 100644 index 00000000..09dd426e --- /dev/null +++ b/src/Orb.Tests/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Plans.ExternalPlanID; + +namespace Orb.Tests.Models.Plans.ExternalPlanID; + +public class ExternalPlanIDFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPlanIDFetchParams { ExternalPlanID = "external_plan_id" }; + + string expectedExternalPlanID = "external_plan_id"; + + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + } +} diff --git a/src/Orb.Tests/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParamsTest.cs b/src/Orb.Tests/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParamsTest.cs new file mode 100644 index 00000000..e7e2ba17 --- /dev/null +++ b/src/Orb.Tests/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParamsTest.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using Orb.Models.Plans.ExternalPlanID; + +namespace Orb.Tests.Models.Plans.ExternalPlanID; + +public class ExternalPlanIDUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPlanIDUpdateParams + { + OtherExternalPlanID = "external_plan_id", + ExternalPlanID = "external_plan_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedOtherExternalPlanID = "external_plan_id"; + string expectedExternalPlanID = "external_plan_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedOtherExternalPlanID, parameters.OtherExternalPlanID); + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ExternalPlanIDUpdateParams + { + OtherExternalPlanID = "external_plan_id", + }; + + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ExternalPlanIDUpdateParams + { + OtherExternalPlanID = "external_plan_id", + + ExternalPlanID = null, + Metadata = null, + }; + + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/Plans/PlanCreateParamsTest.cs b/src/Orb.Tests/Models/Plans/PlanCreateParamsTest.cs new file mode 100644 index 00000000..4a15c487 --- /dev/null +++ b/src/Orb.Tests/Models/Plans/PlanCreateParamsTest.cs @@ -0,0 +1,10114 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Plans; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Plans; + +public class PlanCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PlanCreateParams + { + Currency = "currency", + Name = "name", + Prices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + Adjustments = + [ + new() + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ], + DefaultInvoiceMemo = "default_invoice_memo", + ExternalPlanID = "external_plan_id", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + PlanPhases = + [ + new() + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }, + ], + Status = Status.Active, + }; + + string expectedCurrency = "currency"; + string expectedName = "name"; + List expectedPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ]; + List expectedAdjustments = + [ + new() + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ]; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + string expectedExternalPlanID = "external_plan_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + long expectedNetTerms = 0; + List expectedPlanPhases = + [ + new() + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }, + ]; + ApiEnum expectedStatus = Status.Active; + + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedName, parameters.Name); + Assert.Equal(expectedPrices.Count, parameters.Prices.Count); + for (int i = 0; i < expectedPrices.Count; i++) + { + Assert.Equal(expectedPrices[i], parameters.Prices[i]); + } + Assert.NotNull(parameters.Adjustments); + Assert.Equal(expectedAdjustments.Count, parameters.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], parameters.Adjustments[i]); + } + Assert.Equal(expectedDefaultInvoiceMemo, parameters.DefaultInvoiceMemo); + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedNetTerms, parameters.NetTerms); + Assert.NotNull(parameters.PlanPhases); + Assert.Equal(expectedPlanPhases.Count, parameters.PlanPhases.Count); + for (int i = 0; i < expectedPlanPhases.Count; i++) + { + Assert.Equal(expectedPlanPhases[i], parameters.PlanPhases[i]); + } + Assert.Equal(expectedStatus, parameters.Status); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PlanCreateParams + { + Currency = "currency", + Name = "name", + Prices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + Adjustments = + [ + new() + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ], + DefaultInvoiceMemo = "default_invoice_memo", + ExternalPlanID = "external_plan_id", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + PlanPhases = + [ + new() + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }, + ], + }; + + Assert.Null(parameters.Status); + Assert.False(parameters.RawBodyData.ContainsKey("status")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new PlanCreateParams + { + Currency = "currency", + Name = "name", + Prices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + Adjustments = + [ + new() + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = + Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }, + ], + DefaultInvoiceMemo = "default_invoice_memo", + ExternalPlanID = "external_plan_id", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + PlanPhases = + [ + new() + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }, + ], + + // Null should be interpreted as omitted for these properties + Status = null, + }; + + Assert.Null(parameters.Status); + Assert.False(parameters.RawBodyData.ContainsKey("status")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PlanCreateParams + { + Currency = "currency", + Name = "name", + Prices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + Status = Status.Active, + }; + + Assert.Null(parameters.Adjustments); + Assert.False(parameters.RawBodyData.ContainsKey("adjustments")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + Assert.Null(parameters.PlanPhases); + Assert.False(parameters.RawBodyData.ContainsKey("plan_phases")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PlanCreateParams + { + Currency = "currency", + Name = "name", + Prices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + Status = Status.Active, + + Adjustments = null, + DefaultInvoiceMemo = null, + ExternalPlanID = null, + Metadata = null, + NetTerms = null, + PlanPhases = null, + }; + + Assert.Null(parameters.Adjustments); + Assert.False(parameters.RawBodyData.ContainsKey("adjustments")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + Assert.Null(parameters.PlanPhases); + Assert.False(parameters.RawBodyData.ContainsKey("plan_phases")); + } +} + +public class PriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Price + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + PricePrice expectedPriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceValue, model.PriceValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Price + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Price + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Models::NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + long expectedPlanPhaseOrder = 0; + PricePrice expectedPriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceValue, deserialized.PriceValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Price + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Models::Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = Models::NewAllocationPriceFilterField.ItemID, + Operator = Models::NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Price { }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.PriceValue); + Assert.False(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Price { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Price + { + AllocationPrice = null, + PlanPhaseOrder = null, + PriceValue = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.PriceValue); + Assert.True(model.RawData.ContainsKey("price")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Price + { + AllocationPrice = null, + PlanPhaseOrder = null, + PriceValue = null, + }; + + model.Validate(); + } +} + +public class PricePriceTest : TestBase +{ + [Fact] + public void NewPlanUnitValidationWorks() + { + PricePrice value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredValidationWorks() + { + PricePrice value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkValidationWorks() + { + PricePrice value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + PricePrice value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageValidationWorks() + { + PricePrice value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixValidationWorks() + { + PricePrice value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanThresholdTotalAmountValidationWorks() + { + PricePrice value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageValidationWorks() + { + PricePrice value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredWithMinimumValidationWorks() + { + PricePrice value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredValidationWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumValidationWorks() + { + PricePrice value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanPackageWithAllocationValidationWorks() + { + PricePrice value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithPercentValidationWorks() + { + PricePrice value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithAllocationValidationWorks() + { + PricePrice value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + PricePrice value = new( + new TieredWithProration() + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitWithProrationValidationWorks() + { + PricePrice value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedAllocationValidationWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanBulkWithProrationValidationWorks() + { + PricePrice value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumValidationWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumValidationWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + PricePrice value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameValidationWorks() + { + PricePrice value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanGroupedTieredPackageValidationWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageValidationWorks() + { + PricePrice value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingValidationWorks() + { + PricePrice value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingValidationWorks() + { + PricePrice value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkValidationWorks() + { + PricePrice value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + PricePrice value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanMinimumCompositeValidationWorks() + { + PricePrice value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + PricePrice value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + PricePrice value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewPlanUnitSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanUnitPrice() + { + Cadence = Models::NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanTieredPrice() + { + Cadence = Models::NewPlanTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewPlanBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkPriceModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + PricePrice value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanPackagePrice() + { + Cadence = Models::NewPlanPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanMatrixPrice() + { + Cadence = Models::NewPlanMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanThresholdTotalAmountSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanThresholdTotalAmountPrice() + { + Cadence = Models::NewPlanThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanTieredPackagePrice() + { + Cadence = Models::NewPlanTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredWithMinimumSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanTieredWithMinimumPrice() + { + Cadence = Models::NewPlanTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedTieredPrice() + { + Cadence = Models::NewPlanGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanTieredPackageWithMinimumSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanTieredPackageWithMinimumPrice() + { + Cadence = Models::NewPlanTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanPackageWithAllocationSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanPackageWithAllocationPrice() + { + Cadence = Models::NewPlanPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithPercentSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanUnitWithPercentPrice() + { + Cadence = Models::NewPlanUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithAllocationSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanMatrixWithAllocationPrice() + { + Cadence = Models::NewPlanMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + PricePrice value = new( + new TieredWithProration() + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanUnitWithProrationSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanUnitWithProrationPrice() + { + Cadence = Models::NewPlanUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedAllocationSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedAllocationPrice() + { + Cadence = Models::NewPlanGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanBulkWithProrationSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewPlanBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = Models::NewPlanBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithProratedMinimumSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + PricePrice value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMatrixWithDisplayNameSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanMatrixWithDisplayNamePrice() + { + Cadence = Models::NewPlanMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanGroupedTieredPackageSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanGroupedTieredPackagePrice() + { + Cadence = Models::NewPlanGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMaxGroupTieredPackageSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanMaxGroupTieredPackagePrice() + { + Cadence = Models::NewPlanMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Models::NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanCumulativeGroupedBulkSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanCumulativeGroupedBulkPrice() + { + Cadence = Models::NewPlanCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Models::NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + PricePrice value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewPlanMinimumCompositeSerializationRoundtripWorks() + { + PricePrice value = new( + new Models::NewPlanMinimumCompositePrice() + { + Cadence = Models::NewPlanMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewPlanMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + PricePrice value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + PricePrice value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + model.Validate(); + } +} + +public class TierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class CadenceTest : TestBase +{ + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void Validation_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void SerializationRoundtrip_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithProration + { + Cadence = TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class TieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Custom)] + public void Validation_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class TieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class TieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class PercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void Validation_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void SerializationRoundtrip_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = EventOutputCadence.Annual; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = EventOutputCadence.Annual; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class EventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void Validation_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class EventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + AdjustmentAdjustment expectedAdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustmentValue, model.AdjustmentValue); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + AdjustmentAdjustment expectedAdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }; + long expectedPlanPhaseOrder = 0; + + Assert.Equal(expectedAdjustmentValue, deserialized.AdjustmentValue); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + } + + [Fact] + public void Validation_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + PlanPhaseOrder = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + + PlanPhaseOrder = null, + }; + + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Adjustment + { + AdjustmentValue = new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + }, + + PlanPhaseOrder = null, + }; + + model.Validate(); + } +} + +public class AdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + AdjustmentAdjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + AdjustmentAdjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + AdjustmentAdjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + AdjustmentAdjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + AdjustmentAdjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + AdjustmentAdjustment value = new( + new Models::NewPercentageDiscount() + { + AdjustmentType = Models::NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = Models::NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewPercentageDiscountFilterField.PriceID, + Operator = Models::NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + AdjustmentAdjustment value = new( + new Models::NewUsageDiscount() + { + AdjustmentType = Models::NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = Models::NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewUsageDiscountFilterField.PriceID, + Operator = Models::NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + AdjustmentAdjustment value = new( + new Models::NewAmountDiscount() + { + AdjustmentType = Models::NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = Models::AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewAmountDiscountFilterField.PriceID, + Operator = Models::NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + AdjustmentAdjustment value = new( + new Models::NewMinimum() + { + AdjustmentType = Models::NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = Models::NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMinimumFilterField.PriceID, + Operator = Models::NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + AdjustmentAdjustment value = new( + new Models::NewMaximum() + { + AdjustmentType = Models::NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = Models::NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = Models::NewMaximumFilterField.PriceID, + Operator = Models::NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = Models::NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PlanPhaseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPhase + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }; + + long expectedOrder = 0; + bool expectedAlignBillingWithPhaseStartDate = true; + long expectedDuration = 1; + ApiEnum expectedDurationUnit = DurationUnit.Daily; + + Assert.Equal(expectedOrder, model.Order); + Assert.Equal(expectedAlignBillingWithPhaseStartDate, model.AlignBillingWithPhaseStartDate); + Assert.Equal(expectedDuration, model.Duration); + Assert.Equal(expectedDurationUnit, model.DurationUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPhase + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPhase + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedOrder = 0; + bool expectedAlignBillingWithPhaseStartDate = true; + long expectedDuration = 1; + ApiEnum expectedDurationUnit = DurationUnit.Daily; + + Assert.Equal(expectedOrder, deserialized.Order); + Assert.Equal( + expectedAlignBillingWithPhaseStartDate, + deserialized.AlignBillingWithPhaseStartDate + ); + Assert.Equal(expectedDuration, deserialized.Duration); + Assert.Equal(expectedDurationUnit, deserialized.DurationUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPhase + { + Order = 0, + AlignBillingWithPhaseStartDate = true, + Duration = 1, + DurationUnit = DurationUnit.Daily, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PlanPhase { Order = 0 }; + + Assert.Null(model.AlignBillingWithPhaseStartDate); + Assert.False(model.RawData.ContainsKey("align_billing_with_phase_start_date")); + Assert.Null(model.Duration); + Assert.False(model.RawData.ContainsKey("duration")); + Assert.Null(model.DurationUnit); + Assert.False(model.RawData.ContainsKey("duration_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PlanPhase { Order = 0 }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PlanPhase + { + Order = 0, + + AlignBillingWithPhaseStartDate = null, + Duration = null, + DurationUnit = null, + }; + + Assert.Null(model.AlignBillingWithPhaseStartDate); + Assert.True(model.RawData.ContainsKey("align_billing_with_phase_start_date")); + Assert.Null(model.Duration); + Assert.True(model.RawData.ContainsKey("duration")); + Assert.Null(model.DurationUnit); + Assert.True(model.RawData.ContainsKey("duration_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PlanPhase + { + Order = 0, + + AlignBillingWithPhaseStartDate = null, + Duration = null, + DurationUnit = null, + }; + + model.Validate(); + } +} + +public class DurationUnitTest : TestBase +{ + [Theory] + [InlineData(DurationUnit.Daily)] + [InlineData(DurationUnit.Monthly)] + [InlineData(DurationUnit.Quarterly)] + [InlineData(DurationUnit.SemiAnnual)] + [InlineData(DurationUnit.Annual)] + public void Validation_Works(DurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DurationUnit.Daily)] + [InlineData(DurationUnit.Monthly)] + [InlineData(DurationUnit.Quarterly)] + [InlineData(DurationUnit.SemiAnnual)] + [InlineData(DurationUnit.Annual)] + public void SerializationRoundtrip_Works(DurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Draft)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Draft)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Plans/PlanFetchParamsTest.cs b/src/Orb.Tests/Models/Plans/PlanFetchParamsTest.cs new file mode 100644 index 00000000..4b7ec84a --- /dev/null +++ b/src/Orb.Tests/Models/Plans/PlanFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Plans; + +namespace Orb.Tests.Models.Plans; + +public class PlanFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PlanFetchParams { PlanID = "plan_id" }; + + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedPlanID, parameters.PlanID); + } +} diff --git a/src/Orb.Tests/Models/Plans/PlanListPageResponseTest.cs b/src/Orb.Tests/Models/Plans/PlanListPageResponseTest.cs new file mode 100644 index 00000000..a04f0fc7 --- /dev/null +++ b/src/Orb.Tests/Models/Plans/PlanListPageResponseTest.cs @@ -0,0 +1,1763 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Plans; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Plans; + +public class PlanListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanListPageResponse + { + Data = + [ + new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanListPageResponse + { + Data = + [ + new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanListPageResponse + { + Data = + [ + new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanListPageResponse + { + Data = + [ + new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Plans/PlanListParamsTest.cs b/src/Orb.Tests/Models/Plans/PlanListParamsTest.cs new file mode 100644 index 00000000..183c06cf --- /dev/null +++ b/src/Orb.Tests/Models/Plans/PlanListParamsTest.cs @@ -0,0 +1,185 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Plans; + +namespace Orb.Tests.Models.Plans; + +public class PlanListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PlanListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + Limit = 1, + Status = PlanListParamsStatus.Active, + }; + + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + long expectedLimit = 1; + ApiEnum expectedStatus = PlanListParamsStatus.Active; + + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedStatus, parameters.Status); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PlanListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + Assert.Null(parameters.Status); + Assert.False(parameters.RawQueryData.ContainsKey("status")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new PlanListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + Status = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + Assert.Null(parameters.Status); + Assert.False(parameters.RawQueryData.ContainsKey("status")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PlanListParams { Limit = 1, Status = PlanListParamsStatus.Active }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PlanListParams + { + Limit = 1, + Status = PlanListParamsStatus.Active, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Cursor = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} + +public class PlanListParamsStatusTest : TestBase +{ + [Theory] + [InlineData(PlanListParamsStatus.Active)] + [InlineData(PlanListParamsStatus.Archived)] + [InlineData(PlanListParamsStatus.Draft)] + public void Validation_Works(PlanListParamsStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanListParamsStatus.Active)] + [InlineData(PlanListParamsStatus.Archived)] + [InlineData(PlanListParamsStatus.Draft)] + public void SerializationRoundtrip_Works(PlanListParamsStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Plans/PlanTest.cs b/src/Orb.Tests/Models/Plans/PlanTest.cs new file mode 100644 index 00000000..537c958c --- /dev/null +++ b/src/Orb.Tests/Models/Plans/PlanTest.cs @@ -0,0 +1,2855 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Plans; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Plans; + +public class PlanTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Plan + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }; + + string expectedID = "id"; + List expectedAdjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + BasePlan expectedBasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + string expectedBasePlanID = "base_plan_id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + string expectedDescription = "description"; + Models::SharedDiscount expectedDiscount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPlanID = "external_plan_id"; + string expectedInvoicingCurrency = "invoicing_currency"; + Models::Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Models::Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + string expectedName = "name"; + long expectedNetTerms = 0; + List expectedPlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ]; + List expectedPrices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ]; + Product expectedProduct = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }; + ApiEnum expectedStatus = PlanStatus.Active; + TrialConfig expectedTrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = TrialPeriodUnit.Days, + }; + long expectedVersion = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAdjustments.Count, model.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], model.Adjustments[i]); + } + Assert.Equal(expectedBasePlan, model.BasePlan); + Assert.Equal(expectedBasePlanID, model.BasePlanID); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDefaultInvoiceMemo, model.DefaultInvoiceMemo); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPlanID, model.ExternalPlanID); + Assert.Equal(expectedInvoicingCurrency, model.InvoicingCurrency); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.NotNull(model.PlanPhases); + Assert.Equal(expectedPlanPhases.Count, model.PlanPhases.Count); + for (int i = 0; i < expectedPlanPhases.Count; i++) + { + Assert.Equal(expectedPlanPhases[i], model.PlanPhases[i]); + } + Assert.Equal(expectedPrices.Count, model.Prices.Count); + for (int i = 0; i < expectedPrices.Count; i++) + { + Assert.Equal(expectedPrices[i], model.Prices[i]); + } + Assert.Equal(expectedProduct, model.Product); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTrialConfig, model.TrialConfig); + Assert.Equal(expectedVersion, model.Version); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Plan + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Plan + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + List expectedAdjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ]; + BasePlan expectedBasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + string expectedBasePlanID = "base_plan_id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCurrency = "currency"; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + string expectedDescription = "description"; + Models::SharedDiscount expectedDiscount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPlanID = "external_plan_id"; + string expectedInvoicingCurrency = "invoicing_currency"; + Models::Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Models::Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + string expectedName = "name"; + long expectedNetTerms = 0; + List expectedPlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ]; + List expectedPrices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ]; + Product expectedProduct = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }; + ApiEnum expectedStatus = PlanStatus.Active; + TrialConfig expectedTrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = TrialPeriodUnit.Days, + }; + long expectedVersion = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAdjustments.Count, deserialized.Adjustments.Count); + for (int i = 0; i < expectedAdjustments.Count; i++) + { + Assert.Equal(expectedAdjustments[i], deserialized.Adjustments[i]); + } + Assert.Equal(expectedBasePlan, deserialized.BasePlan); + Assert.Equal(expectedBasePlanID, deserialized.BasePlanID); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDefaultInvoiceMemo, deserialized.DefaultInvoiceMemo); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPlanID, deserialized.ExternalPlanID); + Assert.Equal(expectedInvoicingCurrency, deserialized.InvoicingCurrency); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.NotNull(deserialized.PlanPhases); + Assert.Equal(expectedPlanPhases.Count, deserialized.PlanPhases.Count); + for (int i = 0; i < expectedPlanPhases.Count; i++) + { + Assert.Equal(expectedPlanPhases[i], deserialized.PlanPhases[i]); + } + Assert.Equal(expectedPrices.Count, deserialized.Prices.Count); + for (int i = 0; i < expectedPrices.Count; i++) + { + Assert.Equal(expectedPrices[i], deserialized.Prices[i]); + } + Assert.Equal(expectedProduct, deserialized.Product); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTrialConfig, deserialized.TrialConfig); + Assert.Equal(expectedVersion, deserialized.Version); + } + + [Fact] + public void Validation_Works() + { + var model = new Plan + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }, + Version = 0, + }; + + model.Validate(); + } +} + +public class PlanAdjustmentTest : TestBase +{ + [Fact] + public void PlanPhaseUsageDiscountValidationWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseAmountDiscountValidationWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhasePercentageDiscountValidationWorks() + { + PlanAdjustment value = new( + new Models::PlanPhasePercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseMinimumValidationWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseMaximumValidationWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + value.Validate(); + } + + [Fact] + public void PlanPhaseUsageDiscountSerializationRoundtripWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseAmountDiscountSerializationRoundtripWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseAmountDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhasePercentageDiscountSerializationRoundtripWorks() + { + PlanAdjustment value = new( + new Models::PlanPhasePercentageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PercentageDiscount = 0, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseMinimumSerializationRoundtripWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseMinimumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMinimumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMinimumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PlanPhaseMaximumSerializationRoundtripWorks() + { + PlanAdjustment value = new( + new Models::PlanPhaseMaximumAdjustment() + { + ID = "id", + AdjustmentType = Models::PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseMaximumAdjustmentFilterField.PriceID, + Operator = Models::PlanPhaseMaximumAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + MaximumAmount = "maximum_amount", + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BasePlanTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BasePlan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + string expectedID = "m2t5akQeh2obwxeU"; + string expectedExternalPlanID = "m2t5akQeh2obwxeU"; + string expectedName = "Example plan"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedExternalPlanID, model.ExternalPlanID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BasePlan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BasePlan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "m2t5akQeh2obwxeU"; + string expectedExternalPlanID = "m2t5akQeh2obwxeU"; + string expectedName = "Example plan"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedExternalPlanID, deserialized.ExternalPlanID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new BasePlan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + model.Validate(); + } +} + +public class PlanPlanPhaseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PlanPlanPhase + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }; + + string expectedID = "id"; + string expectedDescription = "description"; + Models::SharedDiscount expectedDiscount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + long expectedDuration = 0; + ApiEnum expectedDurationUnit = + PlanPlanPhaseDurationUnit.Daily; + Models::Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Models::Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + string expectedName = "name"; + long expectedOrder = 0; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedDescription, model.Description); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedDuration, model.Duration); + Assert.Equal(expectedDurationUnit, model.DurationUnit); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedOrder, model.Order); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PlanPlanPhase + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PlanPlanPhase + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedDescription = "description"; + Models::SharedDiscount expectedDiscount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + long expectedDuration = 0; + ApiEnum expectedDurationUnit = + PlanPlanPhaseDurationUnit.Daily; + Models::Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Models::Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + string expectedName = "name"; + long expectedOrder = 0; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedDescription, deserialized.Description); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedDuration, deserialized.Duration); + Assert.Equal(expectedDurationUnit, deserialized.DurationUnit); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedOrder, deserialized.Order); + } + + [Fact] + public void Validation_Works() + { + var model = new PlanPlanPhase + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }; + + model.Validate(); + } +} + +public class PlanPlanPhaseDurationUnitTest : TestBase +{ + [Theory] + [InlineData(PlanPlanPhaseDurationUnit.Daily)] + [InlineData(PlanPlanPhaseDurationUnit.Monthly)] + [InlineData(PlanPlanPhaseDurationUnit.Quarterly)] + [InlineData(PlanPlanPhaseDurationUnit.SemiAnnual)] + [InlineData(PlanPlanPhaseDurationUnit.Annual)] + public void Validation_Works(PlanPlanPhaseDurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanPlanPhaseDurationUnit.Daily)] + [InlineData(PlanPlanPhaseDurationUnit.Monthly)] + [InlineData(PlanPlanPhaseDurationUnit.Quarterly)] + [InlineData(PlanPlanPhaseDurationUnit.SemiAnnual)] + [InlineData(PlanPlanPhaseDurationUnit.Annual)] + public void SerializationRoundtrip_Works(PlanPlanPhaseDurationUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ProductTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Product + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }; + + string expectedID = "id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Product + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Product + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new Product + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }; + + model.Validate(); + } +} + +public class PlanStatusTest : TestBase +{ + [Theory] + [InlineData(PlanStatus.Active)] + [InlineData(PlanStatus.Archived)] + [InlineData(PlanStatus.Draft)] + public void Validation_Works(PlanStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PlanStatus.Active)] + [InlineData(PlanStatus.Archived)] + [InlineData(PlanStatus.Draft)] + public void SerializationRoundtrip_Works(PlanStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TrialConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TrialConfig { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }; + + long expectedTrialPeriod = 0; + ApiEnum expectedTrialPeriodUnit = TrialPeriodUnit.Days; + + Assert.Equal(expectedTrialPeriod, model.TrialPeriod); + Assert.Equal(expectedTrialPeriodUnit, model.TrialPeriodUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TrialConfig { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TrialConfig { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + long expectedTrialPeriod = 0; + ApiEnum expectedTrialPeriodUnit = TrialPeriodUnit.Days; + + Assert.Equal(expectedTrialPeriod, deserialized.TrialPeriod); + Assert.Equal(expectedTrialPeriodUnit, deserialized.TrialPeriodUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new TrialConfig { TrialPeriod = 0, TrialPeriodUnit = TrialPeriodUnit.Days }; + + model.Validate(); + } +} + +public class TrialPeriodUnitTest : TestBase +{ + [Theory] + [InlineData(TrialPeriodUnit.Days)] + public void Validation_Works(TrialPeriodUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TrialPeriodUnit.Days)] + public void SerializationRoundtrip_Works(TrialPeriodUnit rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Plans/PlanUpdateParamsTest.cs b/src/Orb.Tests/Models/Plans/PlanUpdateParamsTest.cs new file mode 100644 index 00000000..5a537195 --- /dev/null +++ b/src/Orb.Tests/Models/Plans/PlanUpdateParamsTest.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using Orb.Models.Plans; + +namespace Orb.Tests.Models.Plans; + +public class PlanUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PlanUpdateParams + { + PlanID = "plan_id", + ExternalPlanID = "external_plan_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedPlanID = "plan_id"; + string expectedExternalPlanID = "external_plan_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PlanUpdateParams { PlanID = "plan_id" }; + + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PlanUpdateParams + { + PlanID = "plan_id", + + ExternalPlanID = null, + Metadata = null, + }; + + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/PriceIntervalTest.cs b/src/Orb.Tests/Models/PriceIntervalTest.cs new file mode 100644 index 00000000..8637a74d --- /dev/null +++ b/src/Orb.Tests/Models/PriceIntervalTest.cs @@ -0,0 +1,875 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PriceIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceInterval + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + string expectedID = "id"; + long expectedBillingCycleDay = 0; + bool expectedCanDeferBilling = true; + DateTimeOffset expectedCurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedCurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedFilter = "filter"; + List expectedFixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ]; + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillingCycleDay, model.BillingCycleDay); + Assert.Equal(expectedCanDeferBilling, model.CanDeferBilling); + Assert.Equal(expectedCurrentBillingPeriodEndDate, model.CurrentBillingPeriodEndDate); + Assert.Equal(expectedCurrentBillingPeriodStartDate, model.CurrentBillingPeriodStartDate); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilter, model.Filter); + Assert.NotNull(model.FixedFeeQuantityTransitions); + Assert.Equal( + expectedFixedFeeQuantityTransitions.Count, + model.FixedFeeQuantityTransitions.Count + ); + for (int i = 0; i < expectedFixedFeeQuantityTransitions.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantityTransitions[i], + model.FixedFeeQuantityTransitions[i] + ); + } + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceInterval + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceInterval + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + long expectedBillingCycleDay = 0; + bool expectedCanDeferBilling = true; + DateTimeOffset expectedCurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedCurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedFilter = "filter"; + List expectedFixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ]; + Price expectedPrice = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillingCycleDay, deserialized.BillingCycleDay); + Assert.Equal(expectedCanDeferBilling, deserialized.CanDeferBilling); + Assert.Equal(expectedCurrentBillingPeriodEndDate, deserialized.CurrentBillingPeriodEndDate); + Assert.Equal( + expectedCurrentBillingPeriodStartDate, + deserialized.CurrentBillingPeriodStartDate + ); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.NotNull(deserialized.FixedFeeQuantityTransitions); + Assert.Equal( + expectedFixedFeeQuantityTransitions.Count, + deserialized.FixedFeeQuantityTransitions.Count + ); + for (int i = 0; i < expectedFixedFeeQuantityTransitions.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantityTransitions[i], + deserialized.FixedFeeQuantityTransitions[i] + ); + } + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceInterval + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/PriceTest.cs b/src/Orb.Tests/Models/PriceTest.cs new file mode 100644 index 00000000..80d5f50f --- /dev/null +++ b/src/Orb.Tests/Models/PriceTest.cs @@ -0,0 +1,66803 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class PriceTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Price value = new( + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Price value = new( + new Tiered() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkValidationWorks() + { + Price value = new( + new Bulk() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Price value = new( + new BulkWithFilters() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void PackageValidationWorks() + { + Price value = new( + new Package() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixValidationWorks() + { + Price value = new( + new Matrix() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void ThresholdTotalAmountValidationWorks() + { + Price value = new( + new ThresholdTotalAmount() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void TieredPackageValidationWorks() + { + Price value = new( + new TieredPackage() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithMinimumValidationWorks() + { + Price value = new( + new TieredWithMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedTieredValidationWorks() + { + Price value = new( + new GroupedTiered() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void TieredPackageWithMinimumValidationWorks() + { + Price value = new( + new TieredPackageWithMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void PackageWithAllocationValidationWorks() + { + Price value = new( + new PackageWithAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void UnitWithPercentValidationWorks() + { + Price value = new( + new UnitWithPercent() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixWithAllocationValidationWorks() + { + Price value = new( + new MatrixWithAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Price value = new( + new TieredWithProration() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void UnitWithProrationValidationWorks() + { + Price value = new( + new UnitWithProration() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedAllocationValidationWorks() + { + Price value = new( + new GroupedAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithProrationValidationWorks() + { + Price value = new( + new BulkWithProration() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithProratedMinimumValidationWorks() + { + Price value = new( + new GroupedWithProratedMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMeteredMinimumValidationWorks() + { + Price value = new( + new GroupedWithMeteredMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Price value = new( + new GroupedWithMinMaxThresholds() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void MatrixWithDisplayNameValidationWorks() + { + Price value = new( + new MatrixWithDisplayName() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedTieredPackageValidationWorks() + { + Price value = new( + new GroupedTieredPackage() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void MaxGroupTieredPackageValidationWorks() + { + Price value = new( + new MaxGroupTieredPackage() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void ScalableMatrixWithUnitPricingValidationWorks() + { + Price value = new( + new ScalableMatrixWithUnitPricing() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = + ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void ScalableMatrixWithTieredPricingValidationWorks() + { + Price value = new( + new ScalableMatrixWithTieredPricing() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = + ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedBulkValidationWorks() + { + Price value = new( + new CumulativeGroupedBulk() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Price value = new( + new CumulativeGroupedAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void MinimumValidationWorks() + { + Price value = new( + new PriceMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Price value = new( + new Percent() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Price value = new( + new EventOutput() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Price value = new( + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Price value = new( + new Tiered() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkSerializationRoundtripWorks() + { + Price value = new( + new Bulk() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Price value = new( + new BulkWithFilters() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PackageSerializationRoundtripWorks() + { + Price value = new( + new Package() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MatrixSerializationRoundtripWorks() + { + Price value = new( + new Matrix() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ThresholdTotalAmountSerializationRoundtripWorks() + { + Price value = new( + new ThresholdTotalAmount() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredPackageSerializationRoundtripWorks() + { + Price value = new( + new TieredPackage() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new TieredWithMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedTieredSerializationRoundtripWorks() + { + Price value = new( + new GroupedTiered() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredPackageWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new TieredPackageWithMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PackageWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new PackageWithAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UnitWithPercentSerializationRoundtripWorks() + { + Price value = new( + new UnitWithPercent() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MatrixWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new MatrixWithAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Price value = new( + new TieredWithProration() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UnitWithProrationSerializationRoundtripWorks() + { + Price value = new( + new UnitWithProration() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new GroupedAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithProrationSerializationRoundtripWorks() + { + Price value = new( + new BulkWithProration() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithProratedMinimumSerializationRoundtripWorks() + { + Price value = new( + new GroupedWithProratedMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Price value = new( + new GroupedWithMeteredMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Price value = new( + new GroupedWithMinMaxThresholds() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MatrixWithDisplayNameSerializationRoundtripWorks() + { + Price value = new( + new MatrixWithDisplayName() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new GroupedTieredPackage() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MaxGroupTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new MaxGroupTieredPackage() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Price value = new( + new ScalableMatrixWithUnitPricing() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = + ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void ScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Price value = new( + new ScalableMatrixWithTieredPricing() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = + ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedBulkSerializationRoundtripWorks() + { + Price value = new( + new CumulativeGroupedBulk() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new CumulativeGroupedAllocation() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void MinimumSerializationRoundtripWorks() + { + Price value = new( + new PriceMinimum() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Price value = new( + new Percent() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Price value = new( + new EventOutput() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class UnitTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = BillingMode.InAdvance; + ApiEnum expectedCadence = UnitCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + UnitConversionRateConfig expectedConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"unit\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = UnitPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedUnitConfig, model.UnitConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = BillingMode.InAdvance; + ApiEnum expectedCadence = UnitCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + UnitConversionRateConfig expectedConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"unit\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = UnitPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedUnitConfig, deserialized.UnitConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Unit + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class BillingModeTest : TestBase +{ + [Theory] + [InlineData(BillingMode.InAdvance)] + [InlineData(BillingMode.InArrear)] + public void Validation_Works(BillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BillingMode.InAdvance)] + [InlineData(BillingMode.InArrear)] + public void SerializationRoundtrip_Works(BillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitCadenceTest : TestBase +{ + [Theory] + [InlineData(UnitCadence.OneTime)] + [InlineData(UnitCadence.Monthly)] + [InlineData(UnitCadence.Quarterly)] + [InlineData(UnitCadence.SemiAnnual)] + [InlineData(UnitCadence.Annual)] + [InlineData(UnitCadence.Custom)] + public void Validation_Works(UnitCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitCadence.OneTime)] + [InlineData(UnitCadence.Monthly)] + [InlineData(UnitCadence.Quarterly)] + [InlineData(UnitCadence.SemiAnnual)] + [InlineData(UnitCadence.Annual)] + [InlineData(UnitCadence.Custom)] + public void SerializationRoundtrip_Works(UnitCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class CompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CompositePriceFilter + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + CompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + CompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CompositePriceFilter + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CompositePriceFilter + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + CompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + CompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CompositePriceFilter + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class CompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(CompositePriceFilterField.PriceID)] + [InlineData(CompositePriceFilterField.ItemID)] + [InlineData(CompositePriceFilterField.PriceType)] + [InlineData(CompositePriceFilterField.Currency)] + [InlineData(CompositePriceFilterField.PricingUnitID)] + public void Validation_Works(CompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CompositePriceFilterField.PriceID)] + [InlineData(CompositePriceFilterField.ItemID)] + [InlineData(CompositePriceFilterField.PriceType)] + [InlineData(CompositePriceFilterField.Currency)] + [InlineData(CompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(CompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class CompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(CompositePriceFilterOperator.Includes)] + [InlineData(CompositePriceFilterOperator.Excludes)] + public void Validation_Works(CompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CompositePriceFilterOperator.Includes)] + [InlineData(CompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(CompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + UnitConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + UnitConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + UnitConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + UnitConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class UnitPriceTypeTest : TestBase +{ + [Theory] + [InlineData(UnitPriceType.UsagePrice)] + [InlineData(UnitPriceType.FixedPrice)] + [InlineData(UnitPriceType.CompositePrice)] + public void Validation_Works(UnitPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitPriceType.UsagePrice)] + [InlineData(UnitPriceType.FixedPrice)] + [InlineData(UnitPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(UnitPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = TieredBillingMode.InAdvance; + ApiEnum expectedCadence = TieredCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"tiered\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = TieredPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedTieredConfig, model.TieredConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = TieredBillingMode.InAdvance; + ApiEnum expectedCadence = TieredCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"tiered\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = TieredPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedTieredConfig, deserialized.TieredConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Tiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredBillingMode.InAdvance, + Cadence = TieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class TieredBillingModeTest : TestBase +{ + [Theory] + [InlineData(TieredBillingMode.InAdvance)] + [InlineData(TieredBillingMode.InArrear)] + public void Validation_Works(TieredBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredBillingMode.InAdvance)] + [InlineData(TieredBillingMode.InArrear)] + public void SerializationRoundtrip_Works(TieredBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredCadence.OneTime)] + [InlineData(TieredCadence.Monthly)] + [InlineData(TieredCadence.Quarterly)] + [InlineData(TieredCadence.SemiAnnual)] + [InlineData(TieredCadence.Annual)] + [InlineData(TieredCadence.Custom)] + public void Validation_Works(TieredCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredCadence.OneTime)] + [InlineData(TieredCadence.Monthly)] + [InlineData(TieredCadence.Quarterly)] + [InlineData(TieredCadence.SemiAnnual)] + [InlineData(TieredCadence.Annual)] + [InlineData(TieredCadence.Custom)] + public void SerializationRoundtrip_Works(TieredCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredCompositePriceFilter + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + TieredCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredCompositePriceFilter + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredCompositePriceFilter + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + TieredCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredCompositePriceFilter + { + Field = TieredCompositePriceFilterField.PriceID, + Operator = TieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class TieredCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(TieredCompositePriceFilterField.PriceID)] + [InlineData(TieredCompositePriceFilterField.ItemID)] + [InlineData(TieredCompositePriceFilterField.PriceType)] + [InlineData(TieredCompositePriceFilterField.Currency)] + [InlineData(TieredCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(TieredCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredCompositePriceFilterField.PriceID)] + [InlineData(TieredCompositePriceFilterField.ItemID)] + [InlineData(TieredCompositePriceFilterField.PriceType)] + [InlineData(TieredCompositePriceFilterField.Currency)] + [InlineData(TieredCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(TieredCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(TieredCompositePriceFilterOperator.Includes)] + [InlineData(TieredCompositePriceFilterOperator.Excludes)] + public void Validation_Works(TieredCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredCompositePriceFilterOperator.Includes)] + [InlineData(TieredCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(TieredCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPriceTypeTest : TestBase +{ + [Theory] + [InlineData(TieredPriceType.UsagePrice)] + [InlineData(TieredPriceType.FixedPrice)] + [InlineData(TieredPriceType.CompositePrice)] + public void Validation_Works(TieredPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPriceType.UsagePrice)] + [InlineData(TieredPriceType.FixedPrice)] + [InlineData(TieredPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(TieredPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = BulkBillingMode.InAdvance; + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = BulkCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + BulkConversionRateConfig expectedConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"bulk\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = BulkPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedBulkConfig, model.BulkConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = BulkBillingMode.InAdvance; + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = BulkCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + BulkConversionRateConfig expectedConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"bulk\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = BulkPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedBulkConfig, deserialized.BulkConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Bulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkBillingMode.InAdvance, + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = BulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class BulkBillingModeTest : TestBase +{ + [Theory] + [InlineData(BulkBillingMode.InAdvance)] + [InlineData(BulkBillingMode.InArrear)] + public void Validation_Works(BulkBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkBillingMode.InAdvance)] + [InlineData(BulkBillingMode.InArrear)] + public void SerializationRoundtrip_Works(BulkBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkCadenceTest : TestBase +{ + [Theory] + [InlineData(BulkCadence.OneTime)] + [InlineData(BulkCadence.Monthly)] + [InlineData(BulkCadence.Quarterly)] + [InlineData(BulkCadence.SemiAnnual)] + [InlineData(BulkCadence.Annual)] + [InlineData(BulkCadence.Custom)] + public void Validation_Works(BulkCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkCadence.OneTime)] + [InlineData(BulkCadence.Monthly)] + [InlineData(BulkCadence.Quarterly)] + [InlineData(BulkCadence.SemiAnnual)] + [InlineData(BulkCadence.Annual)] + [InlineData(BulkCadence.Custom)] + public void SerializationRoundtrip_Works(BulkCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkCompositePriceFilter + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + BulkCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + BulkCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkCompositePriceFilter + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkCompositePriceFilter + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + BulkCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + BulkCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkCompositePriceFilter + { + Field = BulkCompositePriceFilterField.PriceID, + Operator = BulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class BulkCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(BulkCompositePriceFilterField.PriceID)] + [InlineData(BulkCompositePriceFilterField.ItemID)] + [InlineData(BulkCompositePriceFilterField.PriceType)] + [InlineData(BulkCompositePriceFilterField.Currency)] + [InlineData(BulkCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(BulkCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkCompositePriceFilterField.PriceID)] + [InlineData(BulkCompositePriceFilterField.ItemID)] + [InlineData(BulkCompositePriceFilterField.PriceType)] + [InlineData(BulkCompositePriceFilterField.Currency)] + [InlineData(BulkCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(BulkCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(BulkCompositePriceFilterOperator.Includes)] + [InlineData(BulkCompositePriceFilterOperator.Excludes)] + public void Validation_Works(BulkCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkCompositePriceFilterOperator.Includes)] + [InlineData(BulkCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(BulkCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + BulkConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + BulkConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + BulkConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + BulkConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkPriceTypeTest : TestBase +{ + [Theory] + [InlineData(BulkPriceType.UsagePrice)] + [InlineData(BulkPriceType.FixedPrice)] + [InlineData(BulkPriceType.CompositePrice)] + public void Validation_Works(BulkPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkPriceType.UsagePrice)] + [InlineData(BulkPriceType.FixedPrice)] + [InlineData(BulkPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(BulkPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + BulkWithFiltersBillingMode.InAdvance; + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = BulkWithFiltersCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + BulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + BulkWithFiltersPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + BulkWithFiltersBillingMode.InAdvance; + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = BulkWithFiltersCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + BulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + BulkWithFiltersPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithFilters + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithFiltersBillingMode.InAdvance, + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = BulkWithFiltersCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithFiltersPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersBillingModeTest : TestBase +{ + [Theory] + [InlineData(BulkWithFiltersBillingMode.InAdvance)] + [InlineData(BulkWithFiltersBillingMode.InArrear)] + public void Validation_Works(BulkWithFiltersBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithFiltersBillingMode.InAdvance)] + [InlineData(BulkWithFiltersBillingMode.InArrear)] + public void SerializationRoundtrip_Works(BulkWithFiltersBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfigFilter { PropertyKey = "x", PropertyValue = "x" }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfigFilter { PropertyKey = "x", PropertyValue = "x" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfigFilter { PropertyKey = "x", PropertyValue = "x" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfigFilter { PropertyKey = "x", PropertyValue = "x" }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithFiltersConfigTier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithFiltersConfigTier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData(BulkWithFiltersCadence.OneTime)] + [InlineData(BulkWithFiltersCadence.Monthly)] + [InlineData(BulkWithFiltersCadence.Quarterly)] + [InlineData(BulkWithFiltersCadence.SemiAnnual)] + [InlineData(BulkWithFiltersCadence.Annual)] + [InlineData(BulkWithFiltersCadence.Custom)] + public void Validation_Works(BulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithFiltersCadence.OneTime)] + [InlineData(BulkWithFiltersCadence.Monthly)] + [InlineData(BulkWithFiltersCadence.Quarterly)] + [InlineData(BulkWithFiltersCadence.SemiAnnual)] + [InlineData(BulkWithFiltersCadence.Annual)] + [InlineData(BulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works(BulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersCompositePriceFilter + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + BulkWithFiltersCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + BulkWithFiltersCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersCompositePriceFilter + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersCompositePriceFilter + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + BulkWithFiltersCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + BulkWithFiltersCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersCompositePriceFilter + { + Field = BulkWithFiltersCompositePriceFilterField.PriceID, + Operator = BulkWithFiltersCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class BulkWithFiltersCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(BulkWithFiltersCompositePriceFilterField.PriceID)] + [InlineData(BulkWithFiltersCompositePriceFilterField.ItemID)] + [InlineData(BulkWithFiltersCompositePriceFilterField.PriceType)] + [InlineData(BulkWithFiltersCompositePriceFilterField.Currency)] + [InlineData(BulkWithFiltersCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(BulkWithFiltersCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithFiltersCompositePriceFilterField.PriceID)] + [InlineData(BulkWithFiltersCompositePriceFilterField.ItemID)] + [InlineData(BulkWithFiltersCompositePriceFilterField.PriceType)] + [InlineData(BulkWithFiltersCompositePriceFilterField.Currency)] + [InlineData(BulkWithFiltersCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(BulkWithFiltersCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(BulkWithFiltersCompositePriceFilterOperator.Includes)] + [InlineData(BulkWithFiltersCompositePriceFilterOperator.Excludes)] + public void Validation_Works(BulkWithFiltersCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithFiltersCompositePriceFilterOperator.Includes)] + [InlineData(BulkWithFiltersCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(BulkWithFiltersCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + BulkWithFiltersConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + BulkWithFiltersConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + BulkWithFiltersConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + BulkWithFiltersConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersPriceTypeTest : TestBase +{ + [Theory] + [InlineData(BulkWithFiltersPriceType.UsagePrice)] + [InlineData(BulkWithFiltersPriceType.FixedPrice)] + [InlineData(BulkWithFiltersPriceType.CompositePrice)] + public void Validation_Works(BulkWithFiltersPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithFiltersPriceType.UsagePrice)] + [InlineData(BulkWithFiltersPriceType.FixedPrice)] + [InlineData(BulkWithFiltersPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(BulkWithFiltersPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PackageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = PackageBillingMode.InAdvance; + ApiEnum expectedCadence = PackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"package\""); + string expectedName = "name"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = PackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageConfig, model.PackageConfig); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = PackageBillingMode.InAdvance; + ApiEnum expectedCadence = PackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"package\""); + string expectedName = "name"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = PackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageConfig, deserialized.PackageConfig); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Package + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageBillingMode.InAdvance, + Cadence = PackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + PlanPhaseOrder = 0, + PriceType = PackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class PackageBillingModeTest : TestBase +{ + [Theory] + [InlineData(PackageBillingMode.InAdvance)] + [InlineData(PackageBillingMode.InArrear)] + public void Validation_Works(PackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageBillingMode.InAdvance)] + [InlineData(PackageBillingMode.InArrear)] + public void SerializationRoundtrip_Works(PackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PackageCadenceTest : TestBase +{ + [Theory] + [InlineData(PackageCadence.OneTime)] + [InlineData(PackageCadence.Monthly)] + [InlineData(PackageCadence.Quarterly)] + [InlineData(PackageCadence.SemiAnnual)] + [InlineData(PackageCadence.Annual)] + [InlineData(PackageCadence.Custom)] + public void Validation_Works(PackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageCadence.OneTime)] + [InlineData(PackageCadence.Monthly)] + [InlineData(PackageCadence.Quarterly)] + [InlineData(PackageCadence.SemiAnnual)] + [InlineData(PackageCadence.Annual)] + [InlineData(PackageCadence.Custom)] + public void SerializationRoundtrip_Works(PackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PackageCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PackageCompositePriceFilter + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PackageCompositePriceFilter + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PackageCompositePriceFilter + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PackageCompositePriceFilter + { + Field = PackageCompositePriceFilterField.PriceID, + Operator = PackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PackageCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PackageCompositePriceFilterField.PriceID)] + [InlineData(PackageCompositePriceFilterField.ItemID)] + [InlineData(PackageCompositePriceFilterField.PriceType)] + [InlineData(PackageCompositePriceFilterField.Currency)] + [InlineData(PackageCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(PackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageCompositePriceFilterField.PriceID)] + [InlineData(PackageCompositePriceFilterField.ItemID)] + [InlineData(PackageCompositePriceFilterField.PriceType)] + [InlineData(PackageCompositePriceFilterField.Currency)] + [InlineData(PackageCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PackageCompositePriceFilterOperator.Includes)] + [InlineData(PackageCompositePriceFilterOperator.Excludes)] + public void Validation_Works(PackageCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageCompositePriceFilterOperator.Includes)] + [InlineData(PackageCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PackageCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PackagePriceTypeTest : TestBase +{ + [Theory] + [InlineData(PackagePriceType.UsagePrice)] + [InlineData(PackagePriceType.FixedPrice)] + [InlineData(PackagePriceType.CompositePrice)] + public void Validation_Works(PackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackagePriceType.UsagePrice)] + [InlineData(PackagePriceType.FixedPrice)] + [InlineData(PackagePriceType.CompositePrice)] + public void SerializationRoundtrip_Works(PackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = MatrixBillingMode.InAdvance; + ApiEnum expectedCadence = MatrixCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MatrixConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"matrix\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = MatrixPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMatrixConfig, model.MatrixConfig); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = MatrixBillingMode.InAdvance; + ApiEnum expectedCadence = MatrixCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MatrixConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"matrix\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = MatrixPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMatrixConfig, deserialized.MatrixConfig); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Matrix + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixBillingMode.InAdvance, + Cadence = MatrixCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class MatrixBillingModeTest : TestBase +{ + [Theory] + [InlineData(MatrixBillingMode.InAdvance)] + [InlineData(MatrixBillingMode.InArrear)] + public void Validation_Works(MatrixBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixBillingMode.InAdvance)] + [InlineData(MatrixBillingMode.InArrear)] + public void SerializationRoundtrip_Works(MatrixBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixCadenceTest : TestBase +{ + [Theory] + [InlineData(MatrixCadence.OneTime)] + [InlineData(MatrixCadence.Monthly)] + [InlineData(MatrixCadence.Quarterly)] + [InlineData(MatrixCadence.SemiAnnual)] + [InlineData(MatrixCadence.Annual)] + [InlineData(MatrixCadence.Custom)] + public void Validation_Works(MatrixCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixCadence.OneTime)] + [InlineData(MatrixCadence.Monthly)] + [InlineData(MatrixCadence.Quarterly)] + [InlineData(MatrixCadence.SemiAnnual)] + [InlineData(MatrixCadence.Annual)] + [InlineData(MatrixCadence.Custom)] + public void SerializationRoundtrip_Works(MatrixCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixCompositePriceFilter + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MatrixCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MatrixCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixCompositePriceFilter + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixCompositePriceFilter + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MatrixCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MatrixCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixCompositePriceFilter + { + Field = MatrixCompositePriceFilterField.PriceID, + Operator = MatrixCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MatrixCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MatrixCompositePriceFilterField.PriceID)] + [InlineData(MatrixCompositePriceFilterField.ItemID)] + [InlineData(MatrixCompositePriceFilterField.PriceType)] + [InlineData(MatrixCompositePriceFilterField.Currency)] + [InlineData(MatrixCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(MatrixCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixCompositePriceFilterField.PriceID)] + [InlineData(MatrixCompositePriceFilterField.ItemID)] + [InlineData(MatrixCompositePriceFilterField.PriceType)] + [InlineData(MatrixCompositePriceFilterField.Currency)] + [InlineData(MatrixCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MatrixCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MatrixCompositePriceFilterOperator.Includes)] + [InlineData(MatrixCompositePriceFilterOperator.Excludes)] + public void Validation_Works(MatrixCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixCompositePriceFilterOperator.Includes)] + [InlineData(MatrixCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(MatrixCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + MatrixConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + MatrixConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + MatrixConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + MatrixConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixPriceTypeTest : TestBase +{ + [Theory] + [InlineData(MatrixPriceType.UsagePrice)] + [InlineData(MatrixPriceType.FixedPrice)] + [InlineData(MatrixPriceType.CompositePrice)] + public void Validation_Works(MatrixPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixPriceType.UsagePrice)] + [InlineData(MatrixPriceType.FixedPrice)] + [InlineData(MatrixPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(MatrixPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + ThresholdTotalAmountBillingMode.InAdvance; + ApiEnum expectedCadence = + ThresholdTotalAmountCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + ThresholdTotalAmountConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"threshold_total_amount\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + ThresholdTotalAmountPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + ThresholdTotalAmountThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedThresholdTotalAmountConfig, model.ThresholdTotalAmountConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + ThresholdTotalAmountBillingMode.InAdvance; + ApiEnum expectedCadence = + ThresholdTotalAmountCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + ThresholdTotalAmountConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"threshold_total_amount\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + ThresholdTotalAmountPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + ThresholdTotalAmountThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedThresholdTotalAmountConfig, deserialized.ThresholdTotalAmountConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ThresholdTotalAmount + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ThresholdTotalAmountBillingMode.InAdvance, + Cadence = ThresholdTotalAmountCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ThresholdTotalAmountPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class ThresholdTotalAmountBillingModeTest : TestBase +{ + [Theory] + [InlineData(ThresholdTotalAmountBillingMode.InAdvance)] + [InlineData(ThresholdTotalAmountBillingMode.InArrear)] + public void Validation_Works(ThresholdTotalAmountBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ThresholdTotalAmountBillingMode.InAdvance)] + [InlineData(ThresholdTotalAmountBillingMode.InArrear)] + public void SerializationRoundtrip_Works(ThresholdTotalAmountBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountCadenceTest : TestBase +{ + [Theory] + [InlineData(ThresholdTotalAmountCadence.OneTime)] + [InlineData(ThresholdTotalAmountCadence.Monthly)] + [InlineData(ThresholdTotalAmountCadence.Quarterly)] + [InlineData(ThresholdTotalAmountCadence.SemiAnnual)] + [InlineData(ThresholdTotalAmountCadence.Annual)] + [InlineData(ThresholdTotalAmountCadence.Custom)] + public void Validation_Works(ThresholdTotalAmountCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ThresholdTotalAmountCadence.OneTime)] + [InlineData(ThresholdTotalAmountCadence.Monthly)] + [InlineData(ThresholdTotalAmountCadence.Quarterly)] + [InlineData(ThresholdTotalAmountCadence.SemiAnnual)] + [InlineData(ThresholdTotalAmountCadence.Annual)] + [InlineData(ThresholdTotalAmountCadence.Custom)] + public void SerializationRoundtrip_Works(ThresholdTotalAmountCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ThresholdTotalAmountCompositePriceFilter + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + ThresholdTotalAmountCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + ThresholdTotalAmountCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ThresholdTotalAmountCompositePriceFilter + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ThresholdTotalAmountCompositePriceFilter + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + ThresholdTotalAmountCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + ThresholdTotalAmountCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ThresholdTotalAmountCompositePriceFilter + { + Field = ThresholdTotalAmountCompositePriceFilterField.PriceID, + Operator = ThresholdTotalAmountCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class ThresholdTotalAmountCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.PriceID)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.ItemID)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.PriceType)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.Currency)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(ThresholdTotalAmountCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.PriceID)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.ItemID)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.PriceType)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.Currency)] + [InlineData(ThresholdTotalAmountCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(ThresholdTotalAmountCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(ThresholdTotalAmountCompositePriceFilterOperator.Includes)] + [InlineData(ThresholdTotalAmountCompositePriceFilterOperator.Excludes)] + public void Validation_Works(ThresholdTotalAmountCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ThresholdTotalAmountCompositePriceFilterOperator.Includes)] + [InlineData(ThresholdTotalAmountCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + ThresholdTotalAmountCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ThresholdTotalAmountConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ThresholdTotalAmountConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ThresholdTotalAmountConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ThresholdTotalAmountConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountPriceTypeTest : TestBase +{ + [Theory] + [InlineData(ThresholdTotalAmountPriceType.UsagePrice)] + [InlineData(ThresholdTotalAmountPriceType.FixedPrice)] + [InlineData(ThresholdTotalAmountPriceType.CompositePrice)] + public void Validation_Works(ThresholdTotalAmountPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ThresholdTotalAmountPriceType.UsagePrice)] + [InlineData(ThresholdTotalAmountPriceType.FixedPrice)] + [InlineData(ThresholdTotalAmountPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(ThresholdTotalAmountPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountThresholdTotalAmountConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, model.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], model.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, deserialized.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], deserialized.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + model.Validate(); + } +} + +public class ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTableTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedTotalAmount, model.TotalAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedTotalAmount, deserialized.TotalAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + model.Validate(); + } +} + +public class TieredPackageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredPackageBillingMode.InAdvance; + ApiEnum expectedCadence = TieredPackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredPackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_package\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredPackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredPackageTieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedTieredPackageConfig, model.TieredPackageConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredPackageBillingMode.InAdvance; + ApiEnum expectedCadence = TieredPackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredPackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_package\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredPackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredPackageTieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedTieredPackageConfig, deserialized.TieredPackageConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageBillingMode.InAdvance, + Cadence = TieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class TieredPackageBillingModeTest : TestBase +{ + [Theory] + [InlineData(TieredPackageBillingMode.InAdvance)] + [InlineData(TieredPackageBillingMode.InArrear)] + public void Validation_Works(TieredPackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageBillingMode.InAdvance)] + [InlineData(TieredPackageBillingMode.InArrear)] + public void SerializationRoundtrip_Works(TieredPackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredPackageCadence.OneTime)] + [InlineData(TieredPackageCadence.Monthly)] + [InlineData(TieredPackageCadence.Quarterly)] + [InlineData(TieredPackageCadence.SemiAnnual)] + [InlineData(TieredPackageCadence.Annual)] + [InlineData(TieredPackageCadence.Custom)] + public void Validation_Works(TieredPackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageCadence.OneTime)] + [InlineData(TieredPackageCadence.Monthly)] + [InlineData(TieredPackageCadence.Quarterly)] + [InlineData(TieredPackageCadence.SemiAnnual)] + [InlineData(TieredPackageCadence.Annual)] + [InlineData(TieredPackageCadence.Custom)] + public void SerializationRoundtrip_Works(TieredPackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageCompositePriceFilter + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + TieredPackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredPackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageCompositePriceFilter + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageCompositePriceFilter + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + TieredPackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredPackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageCompositePriceFilter + { + Field = TieredPackageCompositePriceFilterField.PriceID, + Operator = TieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class TieredPackageCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(TieredPackageCompositePriceFilterField.PriceID)] + [InlineData(TieredPackageCompositePriceFilterField.ItemID)] + [InlineData(TieredPackageCompositePriceFilterField.PriceType)] + [InlineData(TieredPackageCompositePriceFilterField.Currency)] + [InlineData(TieredPackageCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(TieredPackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageCompositePriceFilterField.PriceID)] + [InlineData(TieredPackageCompositePriceFilterField.ItemID)] + [InlineData(TieredPackageCompositePriceFilterField.PriceType)] + [InlineData(TieredPackageCompositePriceFilterField.Currency)] + [InlineData(TieredPackageCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(TieredPackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(TieredPackageCompositePriceFilterOperator.Includes)] + [InlineData(TieredPackageCompositePriceFilterOperator.Excludes)] + public void Validation_Works(TieredPackageCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageCompositePriceFilterOperator.Includes)] + [InlineData(TieredPackageCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(TieredPackageCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredPackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredPackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredPackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredPackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackagePriceTypeTest : TestBase +{ + [Theory] + [InlineData(TieredPackagePriceType.UsagePrice)] + [InlineData(TieredPackagePriceType.FixedPrice)] + [InlineData(TieredPackagePriceType.CompositePrice)] + public void Validation_Works(TieredPackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackagePriceType.UsagePrice)] + [InlineData(TieredPackagePriceType.FixedPrice)] + [InlineData(TieredPackagePriceType.CompositePrice)] + public void SerializationRoundtrip_Works(TieredPackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageTieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class TieredPackageTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class TieredWithMinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredWithMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + TieredWithMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredWithMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredWithMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredWithMinimumTieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedTieredWithMinimumConfig, model.TieredWithMinimumConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredWithMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + TieredWithMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredWithMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredWithMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredWithMinimumTieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedTieredWithMinimumConfig, deserialized.TieredWithMinimumConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithMinimumBillingMode.InAdvance, + Cadence = TieredWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class TieredWithMinimumBillingModeTest : TestBase +{ + [Theory] + [InlineData(TieredWithMinimumBillingMode.InAdvance)] + [InlineData(TieredWithMinimumBillingMode.InArrear)] + public void Validation_Works(TieredWithMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithMinimumBillingMode.InAdvance)] + [InlineData(TieredWithMinimumBillingMode.InArrear)] + public void SerializationRoundtrip_Works(TieredWithMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredWithMinimumCadence.OneTime)] + [InlineData(TieredWithMinimumCadence.Monthly)] + [InlineData(TieredWithMinimumCadence.Quarterly)] + [InlineData(TieredWithMinimumCadence.SemiAnnual)] + [InlineData(TieredWithMinimumCadence.Annual)] + [InlineData(TieredWithMinimumCadence.Custom)] + public void Validation_Works(TieredWithMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithMinimumCadence.OneTime)] + [InlineData(TieredWithMinimumCadence.Monthly)] + [InlineData(TieredWithMinimumCadence.Quarterly)] + [InlineData(TieredWithMinimumCadence.SemiAnnual)] + [InlineData(TieredWithMinimumCadence.Annual)] + [InlineData(TieredWithMinimumCadence.Custom)] + public void SerializationRoundtrip_Works(TieredWithMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithMinimumCompositePriceFilter + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + TieredWithMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredWithMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithMinimumCompositePriceFilter + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithMinimumCompositePriceFilter + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + TieredWithMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredWithMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithMinimumCompositePriceFilter + { + Field = TieredWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class TieredWithMinimumCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(TieredWithMinimumCompositePriceFilterField.PriceID)] + [InlineData(TieredWithMinimumCompositePriceFilterField.ItemID)] + [InlineData(TieredWithMinimumCompositePriceFilterField.PriceType)] + [InlineData(TieredWithMinimumCompositePriceFilterField.Currency)] + [InlineData(TieredWithMinimumCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(TieredWithMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithMinimumCompositePriceFilterField.PriceID)] + [InlineData(TieredWithMinimumCompositePriceFilterField.ItemID)] + [InlineData(TieredWithMinimumCompositePriceFilterField.PriceType)] + [InlineData(TieredWithMinimumCompositePriceFilterField.Currency)] + [InlineData(TieredWithMinimumCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(TieredWithMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(TieredWithMinimumCompositePriceFilterOperator.Includes)] + [InlineData(TieredWithMinimumCompositePriceFilterOperator.Excludes)] + public void Validation_Works(TieredWithMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithMinimumCompositePriceFilterOperator.Includes)] + [InlineData(TieredWithMinimumCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(TieredWithMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredWithMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredWithMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredWithMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredWithMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(TieredWithMinimumPriceType.UsagePrice)] + [InlineData(TieredWithMinimumPriceType.FixedPrice)] + [InlineData(TieredWithMinimumPriceType.CompositePrice)] + public void Validation_Works(TieredWithMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithMinimumPriceType.UsagePrice)] + [InlineData(TieredWithMinimumPriceType.FixedPrice)] + [InlineData(TieredWithMinimumPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(TieredWithMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumTieredWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, model.HideZeroAmountTiers); + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, deserialized.HideZeroAmountTiers); + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + model.Validate(); + } +} + +public class TieredWithMinimumTieredWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithMinimumTieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class GroupedTieredTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedTieredBillingMode.InAdvance; + ApiEnum expectedCadence = GroupedTieredCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedTieredConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedTieredGroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_tiered\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedTieredPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedGroupedTieredConfig, model.GroupedTieredConfig); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedTieredBillingMode.InAdvance; + ApiEnum expectedCadence = GroupedTieredCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedTieredConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedTieredGroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_tiered\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedTieredPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedGroupedTieredConfig, deserialized.GroupedTieredConfig); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedTiered + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredBillingMode.InAdvance, + Cadence = GroupedTieredCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class GroupedTieredBillingModeTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredBillingMode.InAdvance)] + [InlineData(GroupedTieredBillingMode.InArrear)] + public void Validation_Works(GroupedTieredBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredBillingMode.InAdvance)] + [InlineData(GroupedTieredBillingMode.InArrear)] + public void SerializationRoundtrip_Works(GroupedTieredBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredCadence.OneTime)] + [InlineData(GroupedTieredCadence.Monthly)] + [InlineData(GroupedTieredCadence.Quarterly)] + [InlineData(GroupedTieredCadence.SemiAnnual)] + [InlineData(GroupedTieredCadence.Annual)] + [InlineData(GroupedTieredCadence.Custom)] + public void Validation_Works(GroupedTieredCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredCadence.OneTime)] + [InlineData(GroupedTieredCadence.Monthly)] + [InlineData(GroupedTieredCadence.Quarterly)] + [InlineData(GroupedTieredCadence.SemiAnnual)] + [InlineData(GroupedTieredCadence.Annual)] + [InlineData(GroupedTieredCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedTieredCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredCompositePriceFilter + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + GroupedTieredCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedTieredCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredCompositePriceFilter + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredCompositePriceFilter + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + GroupedTieredCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedTieredCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredCompositePriceFilter + { + Field = GroupedTieredCompositePriceFilterField.PriceID, + Operator = GroupedTieredCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class GroupedTieredCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredCompositePriceFilterField.PriceID)] + [InlineData(GroupedTieredCompositePriceFilterField.ItemID)] + [InlineData(GroupedTieredCompositePriceFilterField.PriceType)] + [InlineData(GroupedTieredCompositePriceFilterField.Currency)] + [InlineData(GroupedTieredCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(GroupedTieredCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredCompositePriceFilterField.PriceID)] + [InlineData(GroupedTieredCompositePriceFilterField.ItemID)] + [InlineData(GroupedTieredCompositePriceFilterField.PriceType)] + [InlineData(GroupedTieredCompositePriceFilterField.Currency)] + [InlineData(GroupedTieredCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(GroupedTieredCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredCompositePriceFilterOperator.Includes)] + [InlineData(GroupedTieredCompositePriceFilterOperator.Excludes)] + public void Validation_Works(GroupedTieredCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredCompositePriceFilterOperator.Includes)] + [InlineData(GroupedTieredCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(GroupedTieredCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedTieredConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedTieredConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedTieredConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedTieredConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredGroupedTieredConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredGroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class GroupedTieredGroupedTieredConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredGroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class GroupedTieredPriceTypeTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredPriceType.UsagePrice)] + [InlineData(GroupedTieredPriceType.FixedPrice)] + [InlineData(GroupedTieredPriceType.CompositePrice)] + public void Validation_Works(GroupedTieredPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredPriceType.UsagePrice)] + [InlineData(GroupedTieredPriceType.FixedPrice)] + [InlineData(GroupedTieredPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(GroupedTieredPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredPackageWithMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + TieredPackageWithMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredPackageWithMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_package_with_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredPackageWithMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredPackageWithMinimumTieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = + new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedTieredPackageWithMinimumConfig, model.TieredPackageWithMinimumConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredPackageWithMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + TieredPackageWithMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredPackageWithMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_package_with_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredPackageWithMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredPackageWithMinimumTieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = + new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedTieredPackageWithMinimumConfig, + deserialized.TieredPackageWithMinimumConfig + ); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredPackageWithMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredPackageWithMinimumBillingMode.InAdvance, + Cadence = TieredPackageWithMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredPackageWithMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class TieredPackageWithMinimumBillingModeTest : TestBase +{ + [Theory] + [InlineData(TieredPackageWithMinimumBillingMode.InAdvance)] + [InlineData(TieredPackageWithMinimumBillingMode.InArrear)] + public void Validation_Works(TieredPackageWithMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageWithMinimumBillingMode.InAdvance)] + [InlineData(TieredPackageWithMinimumBillingMode.InArrear)] + public void SerializationRoundtrip_Works(TieredPackageWithMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredPackageWithMinimumCadence.OneTime)] + [InlineData(TieredPackageWithMinimumCadence.Monthly)] + [InlineData(TieredPackageWithMinimumCadence.Quarterly)] + [InlineData(TieredPackageWithMinimumCadence.SemiAnnual)] + [InlineData(TieredPackageWithMinimumCadence.Annual)] + [InlineData(TieredPackageWithMinimumCadence.Custom)] + public void Validation_Works(TieredPackageWithMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageWithMinimumCadence.OneTime)] + [InlineData(TieredPackageWithMinimumCadence.Monthly)] + [InlineData(TieredPackageWithMinimumCadence.Quarterly)] + [InlineData(TieredPackageWithMinimumCadence.SemiAnnual)] + [InlineData(TieredPackageWithMinimumCadence.Annual)] + [InlineData(TieredPackageWithMinimumCadence.Custom)] + public void SerializationRoundtrip_Works(TieredPackageWithMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageWithMinimumCompositePriceFilter + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + TieredPackageWithMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredPackageWithMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageWithMinimumCompositePriceFilter + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageWithMinimumCompositePriceFilter + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + TieredPackageWithMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredPackageWithMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageWithMinimumCompositePriceFilter + { + Field = TieredPackageWithMinimumCompositePriceFilterField.PriceID, + Operator = TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class TieredPackageWithMinimumCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.PriceID)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.ItemID)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.PriceType)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.Currency)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(TieredPackageWithMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.PriceID)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.ItemID)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.PriceType)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.Currency)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + TieredPackageWithMinimumCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(TieredPackageWithMinimumCompositePriceFilterOperator.Includes)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterOperator.Excludes)] + public void Validation_Works(TieredPackageWithMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageWithMinimumCompositePriceFilterOperator.Includes)] + [InlineData(TieredPackageWithMinimumCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + TieredPackageWithMinimumCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredPackageWithMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredPackageWithMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredPackageWithMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredPackageWithMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(TieredPackageWithMinimumPriceType.UsagePrice)] + [InlineData(TieredPackageWithMinimumPriceType.FixedPrice)] + [InlineData(TieredPackageWithMinimumPriceType.CompositePrice)] + public void Validation_Works(TieredPackageWithMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredPackageWithMinimumPriceType.UsagePrice)] + [InlineData(TieredPackageWithMinimumPriceType.FixedPrice)] + [InlineData(TieredPackageWithMinimumPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(TieredPackageWithMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumTieredPackageWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + model.Validate(); + } +} + +public class TieredPackageWithMinimumTieredPackageWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredPackageWithMinimumTieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class PackageWithAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + PackageWithAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + PackageWithAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PackageWithAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"package_with_allocation\"" + ); + string expectedName = "name"; + PackageWithAllocationPackageWithAllocationConfig expectedPackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + PackageWithAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageWithAllocationConfig, model.PackageWithAllocationConfig); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + PackageWithAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + PackageWithAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PackageWithAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"package_with_allocation\"" + ); + string expectedName = "name"; + PackageWithAllocationPackageWithAllocationConfig expectedPackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + PackageWithAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageWithAllocationConfig, deserialized.PackageWithAllocationConfig); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PackageWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PackageWithAllocationBillingMode.InAdvance, + Cadence = PackageWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + PlanPhaseOrder = 0, + PriceType = PackageWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class PackageWithAllocationBillingModeTest : TestBase +{ + [Theory] + [InlineData(PackageWithAllocationBillingMode.InAdvance)] + [InlineData(PackageWithAllocationBillingMode.InArrear)] + public void Validation_Works(PackageWithAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageWithAllocationBillingMode.InAdvance)] + [InlineData(PackageWithAllocationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(PackageWithAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(PackageWithAllocationCadence.OneTime)] + [InlineData(PackageWithAllocationCadence.Monthly)] + [InlineData(PackageWithAllocationCadence.Quarterly)] + [InlineData(PackageWithAllocationCadence.SemiAnnual)] + [InlineData(PackageWithAllocationCadence.Annual)] + [InlineData(PackageWithAllocationCadence.Custom)] + public void Validation_Works(PackageWithAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageWithAllocationCadence.OneTime)] + [InlineData(PackageWithAllocationCadence.Monthly)] + [InlineData(PackageWithAllocationCadence.Quarterly)] + [InlineData(PackageWithAllocationCadence.SemiAnnual)] + [InlineData(PackageWithAllocationCadence.Annual)] + [InlineData(PackageWithAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(PackageWithAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PackageWithAllocationCompositePriceFilter + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PackageWithAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PackageWithAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PackageWithAllocationCompositePriceFilter + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PackageWithAllocationCompositePriceFilter + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PackageWithAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PackageWithAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PackageWithAllocationCompositePriceFilter + { + Field = PackageWithAllocationCompositePriceFilterField.PriceID, + Operator = PackageWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PackageWithAllocationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PackageWithAllocationCompositePriceFilterField.PriceID)] + [InlineData(PackageWithAllocationCompositePriceFilterField.ItemID)] + [InlineData(PackageWithAllocationCompositePriceFilterField.PriceType)] + [InlineData(PackageWithAllocationCompositePriceFilterField.Currency)] + [InlineData(PackageWithAllocationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(PackageWithAllocationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageWithAllocationCompositePriceFilterField.PriceID)] + [InlineData(PackageWithAllocationCompositePriceFilterField.ItemID)] + [InlineData(PackageWithAllocationCompositePriceFilterField.PriceType)] + [InlineData(PackageWithAllocationCompositePriceFilterField.Currency)] + [InlineData(PackageWithAllocationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + PackageWithAllocationCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PackageWithAllocationCompositePriceFilterOperator.Includes)] + [InlineData(PackageWithAllocationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(PackageWithAllocationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageWithAllocationCompositePriceFilterOperator.Includes)] + [InlineData(PackageWithAllocationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + PackageWithAllocationCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PackageWithAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PackageWithAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PackageWithAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PackageWithAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationPackageWithAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PackageWithAllocationPackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedPackageAmount, model.PackageAmount); + Assert.Equal(expectedPackageSize, model.PackageSize); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PackageWithAllocationPackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PackageWithAllocationPackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedPackageAmount, deserialized.PackageAmount); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + } + + [Fact] + public void Validation_Works() + { + var model = new PackageWithAllocationPackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + model.Validate(); + } +} + +public class PackageWithAllocationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(PackageWithAllocationPriceType.UsagePrice)] + [InlineData(PackageWithAllocationPriceType.FixedPrice)] + [InlineData(PackageWithAllocationPriceType.CompositePrice)] + public void Validation_Works(PackageWithAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PackageWithAllocationPriceType.UsagePrice)] + [InlineData(PackageWithAllocationPriceType.FixedPrice)] + [InlineData(PackageWithAllocationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(PackageWithAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + UnitWithPercentBillingMode.InAdvance; + ApiEnum expectedCadence = UnitWithPercentCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + UnitWithPercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"unit_with_percent\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + UnitWithPercentPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + UnitWithPercentUnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedUnitWithPercentConfig, model.UnitWithPercentConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + UnitWithPercentBillingMode.InAdvance; + ApiEnum expectedCadence = UnitWithPercentCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + UnitWithPercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"unit_with_percent\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + UnitWithPercentPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + UnitWithPercentUnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedUnitWithPercentConfig, deserialized.UnitWithPercentConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new UnitWithPercent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithPercentBillingMode.InAdvance, + Cadence = UnitWithPercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithPercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class UnitWithPercentBillingModeTest : TestBase +{ + [Theory] + [InlineData(UnitWithPercentBillingMode.InAdvance)] + [InlineData(UnitWithPercentBillingMode.InArrear)] + public void Validation_Works(UnitWithPercentBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithPercentBillingMode.InAdvance)] + [InlineData(UnitWithPercentBillingMode.InArrear)] + public void SerializationRoundtrip_Works(UnitWithPercentBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentCadenceTest : TestBase +{ + [Theory] + [InlineData(UnitWithPercentCadence.OneTime)] + [InlineData(UnitWithPercentCadence.Monthly)] + [InlineData(UnitWithPercentCadence.Quarterly)] + [InlineData(UnitWithPercentCadence.SemiAnnual)] + [InlineData(UnitWithPercentCadence.Annual)] + [InlineData(UnitWithPercentCadence.Custom)] + public void Validation_Works(UnitWithPercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithPercentCadence.OneTime)] + [InlineData(UnitWithPercentCadence.Monthly)] + [InlineData(UnitWithPercentCadence.Quarterly)] + [InlineData(UnitWithPercentCadence.SemiAnnual)] + [InlineData(UnitWithPercentCadence.Annual)] + [InlineData(UnitWithPercentCadence.Custom)] + public void SerializationRoundtrip_Works(UnitWithPercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithPercentCompositePriceFilter + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + UnitWithPercentCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + UnitWithPercentCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithPercentCompositePriceFilter + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithPercentCompositePriceFilter + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + UnitWithPercentCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + UnitWithPercentCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithPercentCompositePriceFilter + { + Field = UnitWithPercentCompositePriceFilterField.PriceID, + Operator = UnitWithPercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class UnitWithPercentCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(UnitWithPercentCompositePriceFilterField.PriceID)] + [InlineData(UnitWithPercentCompositePriceFilterField.ItemID)] + [InlineData(UnitWithPercentCompositePriceFilterField.PriceType)] + [InlineData(UnitWithPercentCompositePriceFilterField.Currency)] + [InlineData(UnitWithPercentCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(UnitWithPercentCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithPercentCompositePriceFilterField.PriceID)] + [InlineData(UnitWithPercentCompositePriceFilterField.ItemID)] + [InlineData(UnitWithPercentCompositePriceFilterField.PriceType)] + [InlineData(UnitWithPercentCompositePriceFilterField.Currency)] + [InlineData(UnitWithPercentCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(UnitWithPercentCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(UnitWithPercentCompositePriceFilterOperator.Includes)] + [InlineData(UnitWithPercentCompositePriceFilterOperator.Excludes)] + public void Validation_Works(UnitWithPercentCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithPercentCompositePriceFilterOperator.Includes)] + [InlineData(UnitWithPercentCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(UnitWithPercentCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + UnitWithPercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + UnitWithPercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + UnitWithPercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + UnitWithPercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentPriceTypeTest : TestBase +{ + [Theory] + [InlineData(UnitWithPercentPriceType.UsagePrice)] + [InlineData(UnitWithPercentPriceType.FixedPrice)] + [InlineData(UnitWithPercentPriceType.CompositePrice)] + public void Validation_Works(UnitWithPercentPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithPercentPriceType.UsagePrice)] + [InlineData(UnitWithPercentPriceType.FixedPrice)] + [InlineData(UnitWithPercentPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(UnitWithPercentPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentUnitWithPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithPercentUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, model.Percent); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithPercentUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithPercentUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, deserialized.Percent); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithPercentUnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class MatrixWithAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + MatrixWithAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + MatrixWithAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MatrixWithAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"matrix_with_allocation\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + MatrixWithAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMatrixWithAllocationConfig, model.MatrixWithAllocationConfig); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + MatrixWithAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + MatrixWithAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MatrixWithAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"matrix_with_allocation\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + MatrixWithAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMatrixWithAllocationConfig, deserialized.MatrixWithAllocationConfig); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MatrixWithAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithAllocationBillingMode.InAdvance, + Cadence = MatrixWithAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class MatrixWithAllocationBillingModeTest : TestBase +{ + [Theory] + [InlineData(MatrixWithAllocationBillingMode.InAdvance)] + [InlineData(MatrixWithAllocationBillingMode.InArrear)] + public void Validation_Works(MatrixWithAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithAllocationBillingMode.InAdvance)] + [InlineData(MatrixWithAllocationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(MatrixWithAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(MatrixWithAllocationCadence.OneTime)] + [InlineData(MatrixWithAllocationCadence.Monthly)] + [InlineData(MatrixWithAllocationCadence.Quarterly)] + [InlineData(MatrixWithAllocationCadence.SemiAnnual)] + [InlineData(MatrixWithAllocationCadence.Annual)] + [InlineData(MatrixWithAllocationCadence.Custom)] + public void Validation_Works(MatrixWithAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithAllocationCadence.OneTime)] + [InlineData(MatrixWithAllocationCadence.Monthly)] + [InlineData(MatrixWithAllocationCadence.Quarterly)] + [InlineData(MatrixWithAllocationCadence.SemiAnnual)] + [InlineData(MatrixWithAllocationCadence.Annual)] + [InlineData(MatrixWithAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(MatrixWithAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithAllocationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithAllocationCompositePriceFilter + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MatrixWithAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MatrixWithAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithAllocationCompositePriceFilter + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithAllocationCompositePriceFilter + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MatrixWithAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MatrixWithAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithAllocationCompositePriceFilter + { + Field = MatrixWithAllocationCompositePriceFilterField.PriceID, + Operator = MatrixWithAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MatrixWithAllocationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MatrixWithAllocationCompositePriceFilterField.PriceID)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.ItemID)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.PriceType)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.Currency)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(MatrixWithAllocationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithAllocationCompositePriceFilterField.PriceID)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.ItemID)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.PriceType)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.Currency)] + [InlineData(MatrixWithAllocationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(MatrixWithAllocationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithAllocationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MatrixWithAllocationCompositePriceFilterOperator.Includes)] + [InlineData(MatrixWithAllocationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(MatrixWithAllocationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithAllocationCompositePriceFilterOperator.Includes)] + [InlineData(MatrixWithAllocationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + MatrixWithAllocationCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + MatrixWithAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + MatrixWithAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + MatrixWithAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + MatrixWithAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithAllocationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(MatrixWithAllocationPriceType.UsagePrice)] + [InlineData(MatrixWithAllocationPriceType.FixedPrice)] + [InlineData(MatrixWithAllocationPriceType.CompositePrice)] + public void Validation_Works(MatrixWithAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithAllocationPriceType.UsagePrice)] + [InlineData(MatrixWithAllocationPriceType.FixedPrice)] + [InlineData(MatrixWithAllocationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(MatrixWithAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredWithProrationBillingMode.InAdvance; + ApiEnum expectedCadence = + TieredWithProrationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredWithProrationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + TieredWithProrationBillingMode.InAdvance; + ApiEnum expectedCadence = + TieredWithProrationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + TieredWithProrationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + TieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = TieredWithProrationBillingMode.InAdvance, + Cadence = TieredWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = TieredWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class TieredWithProrationBillingModeTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationBillingMode.InAdvance)] + [InlineData(TieredWithProrationBillingMode.InArrear)] + public void Validation_Works(TieredWithProrationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationBillingMode.InAdvance)] + [InlineData(TieredWithProrationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(TieredWithProrationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.Custom)] + public void Validation_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationCadence.OneTime)] + [InlineData(TieredWithProrationCadence.Monthly)] + [InlineData(TieredWithProrationCadence.Quarterly)] + [InlineData(TieredWithProrationCadence.SemiAnnual)] + [InlineData(TieredWithProrationCadence.Annual)] + [InlineData(TieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationCompositePriceFilter + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + TieredWithProrationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredWithProrationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationCompositePriceFilter + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationCompositePriceFilter + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + TieredWithProrationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + TieredWithProrationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationCompositePriceFilter + { + Field = TieredWithProrationCompositePriceFilterField.PriceID, + Operator = TieredWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class TieredWithProrationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationCompositePriceFilterField.PriceID)] + [InlineData(TieredWithProrationCompositePriceFilterField.ItemID)] + [InlineData(TieredWithProrationCompositePriceFilterField.PriceType)] + [InlineData(TieredWithProrationCompositePriceFilterField.Currency)] + [InlineData(TieredWithProrationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(TieredWithProrationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationCompositePriceFilterField.PriceID)] + [InlineData(TieredWithProrationCompositePriceFilterField.ItemID)] + [InlineData(TieredWithProrationCompositePriceFilterField.PriceType)] + [InlineData(TieredWithProrationCompositePriceFilterField.Currency)] + [InlineData(TieredWithProrationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(TieredWithProrationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationCompositePriceFilterOperator.Includes)] + [InlineData(TieredWithProrationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(TieredWithProrationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationCompositePriceFilterOperator.Includes)] + [InlineData(TieredWithProrationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + TieredWithProrationCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + TieredWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + TieredWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(TieredWithProrationPriceType.UsagePrice)] + [InlineData(TieredWithProrationPriceType.FixedPrice)] + [InlineData(TieredWithProrationPriceType.CompositePrice)] + public void Validation_Works(TieredWithProrationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TieredWithProrationPriceType.UsagePrice)] + [InlineData(TieredWithProrationPriceType.FixedPrice)] + [InlineData(TieredWithProrationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(TieredWithProrationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationTieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class TieredWithProrationTieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class UnitWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + UnitWithProrationBillingMode.InAdvance; + ApiEnum expectedCadence = + UnitWithProrationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + UnitWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"unit_with_proration\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + UnitWithProrationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + UnitWithProrationUnitWithProrationConfig expectedUnitWithProrationConfig = new( + "unit_amount" + ); + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedUnitWithProrationConfig, model.UnitWithProrationConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + UnitWithProrationBillingMode.InAdvance; + ApiEnum expectedCadence = + UnitWithProrationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + UnitWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"unit_with_proration\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + UnitWithProrationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + UnitWithProrationUnitWithProrationConfig expectedUnitWithProrationConfig = new( + "unit_amount" + ); + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedUnitWithProrationConfig, deserialized.UnitWithProrationConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new UnitWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = UnitWithProrationBillingMode.InAdvance, + Cadence = UnitWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitWithProrationConfig = new("unit_amount"), + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class UnitWithProrationBillingModeTest : TestBase +{ + [Theory] + [InlineData(UnitWithProrationBillingMode.InAdvance)] + [InlineData(UnitWithProrationBillingMode.InArrear)] + public void Validation_Works(UnitWithProrationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithProrationBillingMode.InAdvance)] + [InlineData(UnitWithProrationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(UnitWithProrationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(UnitWithProrationCadence.OneTime)] + [InlineData(UnitWithProrationCadence.Monthly)] + [InlineData(UnitWithProrationCadence.Quarterly)] + [InlineData(UnitWithProrationCadence.SemiAnnual)] + [InlineData(UnitWithProrationCadence.Annual)] + [InlineData(UnitWithProrationCadence.Custom)] + public void Validation_Works(UnitWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithProrationCadence.OneTime)] + [InlineData(UnitWithProrationCadence.Monthly)] + [InlineData(UnitWithProrationCadence.Quarterly)] + [InlineData(UnitWithProrationCadence.SemiAnnual)] + [InlineData(UnitWithProrationCadence.Annual)] + [InlineData(UnitWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(UnitWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithProrationCompositePriceFilter + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + UnitWithProrationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + UnitWithProrationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithProrationCompositePriceFilter + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithProrationCompositePriceFilter + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + UnitWithProrationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + UnitWithProrationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithProrationCompositePriceFilter + { + Field = UnitWithProrationCompositePriceFilterField.PriceID, + Operator = UnitWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class UnitWithProrationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(UnitWithProrationCompositePriceFilterField.PriceID)] + [InlineData(UnitWithProrationCompositePriceFilterField.ItemID)] + [InlineData(UnitWithProrationCompositePriceFilterField.PriceType)] + [InlineData(UnitWithProrationCompositePriceFilterField.Currency)] + [InlineData(UnitWithProrationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(UnitWithProrationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithProrationCompositePriceFilterField.PriceID)] + [InlineData(UnitWithProrationCompositePriceFilterField.ItemID)] + [InlineData(UnitWithProrationCompositePriceFilterField.PriceType)] + [InlineData(UnitWithProrationCompositePriceFilterField.Currency)] + [InlineData(UnitWithProrationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(UnitWithProrationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(UnitWithProrationCompositePriceFilterOperator.Includes)] + [InlineData(UnitWithProrationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(UnitWithProrationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithProrationCompositePriceFilterOperator.Includes)] + [InlineData(UnitWithProrationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(UnitWithProrationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + UnitWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + UnitWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + UnitWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + UnitWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(UnitWithProrationPriceType.UsagePrice)] + [InlineData(UnitWithProrationPriceType.FixedPrice)] + [InlineData(UnitWithProrationPriceType.CompositePrice)] + public void Validation_Works(UnitWithProrationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnitWithProrationPriceType.UsagePrice)] + [InlineData(UnitWithProrationPriceType.FixedPrice)] + [InlineData(UnitWithProrationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(UnitWithProrationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationUnitWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitWithProrationUnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitWithProrationUnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitWithProrationUnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitWithProrationUnitWithProrationConfig { UnitAmount = "unit_amount" }; + + model.Validate(); + } +} + +public class GroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedAllocationGroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_allocation\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedGroupedAllocationConfig, model.GroupedAllocationConfig); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedAllocationGroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_allocation\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedGroupedAllocationConfig, deserialized.GroupedAllocationConfig); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedAllocationBillingMode.InAdvance, + Cadence = GroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class GroupedAllocationBillingModeTest : TestBase +{ + [Theory] + [InlineData(GroupedAllocationBillingMode.InAdvance)] + [InlineData(GroupedAllocationBillingMode.InArrear)] + public void Validation_Works(GroupedAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedAllocationBillingMode.InAdvance)] + [InlineData(GroupedAllocationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(GroupedAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedAllocationCadence.OneTime)] + [InlineData(GroupedAllocationCadence.Monthly)] + [InlineData(GroupedAllocationCadence.Quarterly)] + [InlineData(GroupedAllocationCadence.SemiAnnual)] + [InlineData(GroupedAllocationCadence.Annual)] + [InlineData(GroupedAllocationCadence.Custom)] + public void Validation_Works(GroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedAllocationCadence.OneTime)] + [InlineData(GroupedAllocationCadence.Monthly)] + [InlineData(GroupedAllocationCadence.Quarterly)] + [InlineData(GroupedAllocationCadence.SemiAnnual)] + [InlineData(GroupedAllocationCadence.Annual)] + [InlineData(GroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedAllocationCompositePriceFilter + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + GroupedAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedAllocationCompositePriceFilter + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedAllocationCompositePriceFilter + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + GroupedAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedAllocationCompositePriceFilter + { + Field = GroupedAllocationCompositePriceFilterField.PriceID, + Operator = GroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class GroupedAllocationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(GroupedAllocationCompositePriceFilterField.PriceID)] + [InlineData(GroupedAllocationCompositePriceFilterField.ItemID)] + [InlineData(GroupedAllocationCompositePriceFilterField.PriceType)] + [InlineData(GroupedAllocationCompositePriceFilterField.Currency)] + [InlineData(GroupedAllocationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(GroupedAllocationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedAllocationCompositePriceFilterField.PriceID)] + [InlineData(GroupedAllocationCompositePriceFilterField.ItemID)] + [InlineData(GroupedAllocationCompositePriceFilterField.PriceType)] + [InlineData(GroupedAllocationCompositePriceFilterField.Currency)] + [InlineData(GroupedAllocationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(GroupedAllocationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(GroupedAllocationCompositePriceFilterOperator.Includes)] + [InlineData(GroupedAllocationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(GroupedAllocationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedAllocationCompositePriceFilterOperator.Includes)] + [InlineData(GroupedAllocationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(GroupedAllocationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedAllocationGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedOverageUnitRate, model.OverageUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedAllocationGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedAllocationGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedOverageUnitRate, deserialized.OverageUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedAllocationGroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedAllocationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(GroupedAllocationPriceType.UsagePrice)] + [InlineData(GroupedAllocationPriceType.FixedPrice)] + [InlineData(GroupedAllocationPriceType.CompositePrice)] + public void Validation_Works(GroupedAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedAllocationPriceType.UsagePrice)] + [InlineData(GroupedAllocationPriceType.FixedPrice)] + [InlineData(GroupedAllocationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(GroupedAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + BulkWithProrationBillingMode.InAdvance; + BulkWithProrationBulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum expectedCadence = + BulkWithProrationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + BulkWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_proration\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + BulkWithProrationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedBulkWithProrationConfig, model.BulkWithProrationConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + BulkWithProrationBillingMode.InAdvance; + BulkWithProrationBulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum expectedCadence = + BulkWithProrationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + BulkWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_proration\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + BulkWithProrationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedBulkWithProrationConfig, deserialized.BulkWithProrationConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithProration + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = BulkWithProrationBillingMode.InAdvance, + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = BulkWithProrationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = BulkWithProrationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class BulkWithProrationBillingModeTest : TestBase +{ + [Theory] + [InlineData(BulkWithProrationBillingMode.InAdvance)] + [InlineData(BulkWithProrationBillingMode.InArrear)] + public void Validation_Works(BulkWithProrationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithProrationBillingMode.InAdvance)] + [InlineData(BulkWithProrationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(BulkWithProrationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithProrationBulkWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithProrationBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithProrationBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithProrationBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithProrationBulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class BulkWithProrationBulkWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithProrationBulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class BulkWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(BulkWithProrationCadence.OneTime)] + [InlineData(BulkWithProrationCadence.Monthly)] + [InlineData(BulkWithProrationCadence.Quarterly)] + [InlineData(BulkWithProrationCadence.SemiAnnual)] + [InlineData(BulkWithProrationCadence.Annual)] + [InlineData(BulkWithProrationCadence.Custom)] + public void Validation_Works(BulkWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithProrationCadence.OneTime)] + [InlineData(BulkWithProrationCadence.Monthly)] + [InlineData(BulkWithProrationCadence.Quarterly)] + [InlineData(BulkWithProrationCadence.SemiAnnual)] + [InlineData(BulkWithProrationCadence.Annual)] + [InlineData(BulkWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(BulkWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithProrationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithProrationCompositePriceFilter + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + BulkWithProrationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + BulkWithProrationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithProrationCompositePriceFilter + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithProrationCompositePriceFilter + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + BulkWithProrationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + BulkWithProrationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithProrationCompositePriceFilter + { + Field = BulkWithProrationCompositePriceFilterField.PriceID, + Operator = BulkWithProrationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class BulkWithProrationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(BulkWithProrationCompositePriceFilterField.PriceID)] + [InlineData(BulkWithProrationCompositePriceFilterField.ItemID)] + [InlineData(BulkWithProrationCompositePriceFilterField.PriceType)] + [InlineData(BulkWithProrationCompositePriceFilterField.Currency)] + [InlineData(BulkWithProrationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(BulkWithProrationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithProrationCompositePriceFilterField.PriceID)] + [InlineData(BulkWithProrationCompositePriceFilterField.ItemID)] + [InlineData(BulkWithProrationCompositePriceFilterField.PriceType)] + [InlineData(BulkWithProrationCompositePriceFilterField.Currency)] + [InlineData(BulkWithProrationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(BulkWithProrationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithProrationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(BulkWithProrationCompositePriceFilterOperator.Includes)] + [InlineData(BulkWithProrationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(BulkWithProrationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithProrationCompositePriceFilterOperator.Includes)] + [InlineData(BulkWithProrationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(BulkWithProrationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + BulkWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + BulkWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + BulkWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + BulkWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithProrationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(BulkWithProrationPriceType.UsagePrice)] + [InlineData(BulkWithProrationPriceType.FixedPrice)] + [InlineData(BulkWithProrationPriceType.CompositePrice)] + public void Validation_Works(BulkWithProrationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(BulkWithProrationPriceType.UsagePrice)] + [InlineData(BulkWithProrationPriceType.FixedPrice)] + [InlineData(BulkWithProrationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(BulkWithProrationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedWithProratedMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedWithProratedMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedWithProratedMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedWithProratedMinimumGroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = + new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_prorated_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedWithProratedMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + model.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedWithProratedMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedWithProratedMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedWithProratedMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedWithProratedMinimumGroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = + new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_prorated_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedWithProratedMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + deserialized.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithProratedMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithProratedMinimumBillingMode.InAdvance, + Cadence = GroupedWithProratedMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithProratedMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class GroupedWithProratedMinimumBillingModeTest : TestBase +{ + [Theory] + [InlineData(GroupedWithProratedMinimumBillingMode.InAdvance)] + [InlineData(GroupedWithProratedMinimumBillingMode.InArrear)] + public void Validation_Works(GroupedWithProratedMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithProratedMinimumBillingMode.InAdvance)] + [InlineData(GroupedWithProratedMinimumBillingMode.InArrear)] + public void SerializationRoundtrip_Works(GroupedWithProratedMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithProratedMinimumCadence.OneTime)] + [InlineData(GroupedWithProratedMinimumCadence.Monthly)] + [InlineData(GroupedWithProratedMinimumCadence.Quarterly)] + [InlineData(GroupedWithProratedMinimumCadence.SemiAnnual)] + [InlineData(GroupedWithProratedMinimumCadence.Annual)] + [InlineData(GroupedWithProratedMinimumCadence.Custom)] + public void Validation_Works(GroupedWithProratedMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithProratedMinimumCadence.OneTime)] + [InlineData(GroupedWithProratedMinimumCadence.Monthly)] + [InlineData(GroupedWithProratedMinimumCadence.Quarterly)] + [InlineData(GroupedWithProratedMinimumCadence.SemiAnnual)] + [InlineData(GroupedWithProratedMinimumCadence.Annual)] + [InlineData(GroupedWithProratedMinimumCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithProratedMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithProratedMinimumCompositePriceFilter + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + GroupedWithProratedMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedWithProratedMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithProratedMinimumCompositePriceFilter + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithProratedMinimumCompositePriceFilter + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + GroupedWithProratedMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedWithProratedMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithProratedMinimumCompositePriceFilter + { + Field = GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class GroupedWithProratedMinimumCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.PriceID)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.ItemID)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.PriceType)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.Currency)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(GroupedWithProratedMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.PriceID)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.ItemID)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.PriceType)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.Currency)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + GroupedWithProratedMinimumCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterOperator.Includes)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterOperator.Excludes)] + public void Validation_Works(GroupedWithProratedMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterOperator.Includes)] + [InlineData(GroupedWithProratedMinimumCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + GroupedWithProratedMinimumCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithProratedMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithProratedMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithProratedMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithProratedMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumGroupedWithProratedMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithProratedMinimumGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedUnitRate, model.UnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithProratedMinimumGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithProratedMinimumGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedUnitRate, deserialized.UnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithProratedMinimumGroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithProratedMinimumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(GroupedWithProratedMinimumPriceType.UsagePrice)] + [InlineData(GroupedWithProratedMinimumPriceType.FixedPrice)] + [InlineData(GroupedWithProratedMinimumPriceType.CompositePrice)] + public void Validation_Works(GroupedWithProratedMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithProratedMinimumPriceType.UsagePrice)] + [InlineData(GroupedWithProratedMinimumPriceType.FixedPrice)] + [InlineData(GroupedWithProratedMinimumPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(GroupedWithProratedMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedWithMeteredMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedWithMeteredMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedWithMeteredMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = + new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_metered_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedWithMeteredMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + model.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedWithMeteredMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedWithMeteredMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedWithMeteredMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = + new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_metered_minimum\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedWithMeteredMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + deserialized.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithMeteredMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMeteredMinimumBillingMode.InAdvance, + Cadence = GroupedWithMeteredMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMeteredMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMeteredMinimumBillingModeTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMeteredMinimumBillingMode.InAdvance)] + [InlineData(GroupedWithMeteredMinimumBillingMode.InArrear)] + public void Validation_Works(GroupedWithMeteredMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMeteredMinimumBillingMode.InAdvance)] + [InlineData(GroupedWithMeteredMinimumBillingMode.InArrear)] + public void SerializationRoundtrip_Works(GroupedWithMeteredMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMeteredMinimumCadence.OneTime)] + [InlineData(GroupedWithMeteredMinimumCadence.Monthly)] + [InlineData(GroupedWithMeteredMinimumCadence.Quarterly)] + [InlineData(GroupedWithMeteredMinimumCadence.SemiAnnual)] + [InlineData(GroupedWithMeteredMinimumCadence.Annual)] + [InlineData(GroupedWithMeteredMinimumCadence.Custom)] + public void Validation_Works(GroupedWithMeteredMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMeteredMinimumCadence.OneTime)] + [InlineData(GroupedWithMeteredMinimumCadence.Monthly)] + [InlineData(GroupedWithMeteredMinimumCadence.Quarterly)] + [InlineData(GroupedWithMeteredMinimumCadence.SemiAnnual)] + [InlineData(GroupedWithMeteredMinimumCadence.Annual)] + [InlineData(GroupedWithMeteredMinimumCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithMeteredMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumCompositePriceFilter + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + GroupedWithMeteredMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumCompositePriceFilter + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMeteredMinimumCompositePriceFilter + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + GroupedWithMeteredMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMeteredMinimumCompositePriceFilter + { + Field = GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + Operator = GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class GroupedWithMeteredMinimumCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.PriceID)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.ItemID)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.PriceType)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.Currency)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(GroupedWithMeteredMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.PriceID)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.ItemID)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.PriceType)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.Currency)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + GroupedWithMeteredMinimumCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterOperator.Excludes)] + public void Validation_Works(GroupedWithMeteredMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes)] + [InlineData(GroupedWithMeteredMinimumCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + GroupedWithMeteredMinimumCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithMeteredMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithMeteredMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithMeteredMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithMeteredMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, model.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, model.PricingKey); + Assert.Equal(expectedScalingFactors.Count, model.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], model.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, model.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, deserialized.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, deserialized.PricingKey); + Assert.Equal(expectedScalingFactors.Count, deserialized.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], deserialized.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, deserialized.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactor = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = [new() { PricingValue = "pricing_value", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string expectedScalingFactor = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedScalingValue, model.ScalingValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedScalingFactor = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedScalingValue, deserialized.ScalingValue); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor + { + ScalingFactor = "scaling_factor", + ScalingValue = "scaling_value", + }; + + model.Validate(); + } +} + +public class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPricingValue, model.PricingValue); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPricingValue, deserialized.PricingValue); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount + { + PricingValue = "pricing_value", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class GroupedWithMeteredMinimumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMeteredMinimumPriceType.UsagePrice)] + [InlineData(GroupedWithMeteredMinimumPriceType.FixedPrice)] + [InlineData(GroupedWithMeteredMinimumPriceType.CompositePrice)] + public void Validation_Works(GroupedWithMeteredMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMeteredMinimumPriceType.UsagePrice)] + [InlineData(GroupedWithMeteredMinimumPriceType.FixedPrice)] + [InlineData(GroupedWithMeteredMinimumPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(GroupedWithMeteredMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedWithMinMaxThresholdsBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedWithMinMaxThresholdsPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedWithMinMaxThresholdsBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedWithMinMaxThresholdsPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedWithMinMaxThresholdsBillingMode.InAdvance, + Cadence = GroupedWithMinMaxThresholdsCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedWithMinMaxThresholdsPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsBillingModeTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsBillingMode.InAdvance)] + [InlineData(GroupedWithMinMaxThresholdsBillingMode.InArrear)] + public void Validation_Works(GroupedWithMinMaxThresholdsBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsBillingMode.InAdvance)] + [InlineData(GroupedWithMinMaxThresholdsBillingMode.InArrear)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsCompositePriceFilter + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsCompositePriceFilter + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholdsCompositePriceFilter + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholdsCompositePriceFilter + { + Field = GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + Operator = GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.ItemID)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceType)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.Currency)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(GroupedWithMinMaxThresholdsCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.ItemID)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceType)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.Currency)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + GroupedWithMinMaxThresholdsCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Excludes)] + public void Validation_Works(GroupedWithMinMaxThresholdsCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes)] + [InlineData(GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + GroupedWithMinMaxThresholdsCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsPriceTypeTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsPriceType.UsagePrice)] + [InlineData(GroupedWithMinMaxThresholdsPriceType.FixedPrice)] + [InlineData(GroupedWithMinMaxThresholdsPriceType.CompositePrice)] + public void Validation_Works(GroupedWithMinMaxThresholdsPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsPriceType.UsagePrice)] + [InlineData(GroupedWithMinMaxThresholdsPriceType.FixedPrice)] + [InlineData(GroupedWithMinMaxThresholdsPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + MatrixWithDisplayNameBillingMode.InAdvance; + ApiEnum expectedCadence = + MatrixWithDisplayNameCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MatrixWithDisplayNameConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MatrixWithDisplayNameMatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"matrix_with_display_name\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + MatrixWithDisplayNamePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMatrixWithDisplayNameConfig, model.MatrixWithDisplayNameConfig); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + MatrixWithDisplayNameBillingMode.InAdvance; + ApiEnum expectedCadence = + MatrixWithDisplayNameCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MatrixWithDisplayNameConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MatrixWithDisplayNameMatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"matrix_with_display_name\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + MatrixWithDisplayNamePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMatrixWithDisplayNameConfig, deserialized.MatrixWithDisplayNameConfig); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MatrixWithDisplayName + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MatrixWithDisplayNameBillingMode.InAdvance, + Cadence = MatrixWithDisplayNameCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MatrixWithDisplayNamePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class MatrixWithDisplayNameBillingModeTest : TestBase +{ + [Theory] + [InlineData(MatrixWithDisplayNameBillingMode.InAdvance)] + [InlineData(MatrixWithDisplayNameBillingMode.InArrear)] + public void Validation_Works(MatrixWithDisplayNameBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithDisplayNameBillingMode.InAdvance)] + [InlineData(MatrixWithDisplayNameBillingMode.InArrear)] + public void SerializationRoundtrip_Works(MatrixWithDisplayNameBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameCadenceTest : TestBase +{ + [Theory] + [InlineData(MatrixWithDisplayNameCadence.OneTime)] + [InlineData(MatrixWithDisplayNameCadence.Monthly)] + [InlineData(MatrixWithDisplayNameCadence.Quarterly)] + [InlineData(MatrixWithDisplayNameCadence.SemiAnnual)] + [InlineData(MatrixWithDisplayNameCadence.Annual)] + [InlineData(MatrixWithDisplayNameCadence.Custom)] + public void Validation_Works(MatrixWithDisplayNameCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithDisplayNameCadence.OneTime)] + [InlineData(MatrixWithDisplayNameCadence.Monthly)] + [InlineData(MatrixWithDisplayNameCadence.Quarterly)] + [InlineData(MatrixWithDisplayNameCadence.SemiAnnual)] + [InlineData(MatrixWithDisplayNameCadence.Annual)] + [InlineData(MatrixWithDisplayNameCadence.Custom)] + public void SerializationRoundtrip_Works(MatrixWithDisplayNameCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithDisplayNameCompositePriceFilter + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MatrixWithDisplayNameCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MatrixWithDisplayNameCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithDisplayNameCompositePriceFilter + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithDisplayNameCompositePriceFilter + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MatrixWithDisplayNameCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MatrixWithDisplayNameCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithDisplayNameCompositePriceFilter + { + Field = MatrixWithDisplayNameCompositePriceFilterField.PriceID, + Operator = MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MatrixWithDisplayNameCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.PriceID)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.ItemID)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.PriceType)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.Currency)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(MatrixWithDisplayNameCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.PriceID)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.ItemID)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.PriceType)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.Currency)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + MatrixWithDisplayNameCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MatrixWithDisplayNameCompositePriceFilterOperator.Includes)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterOperator.Excludes)] + public void Validation_Works(MatrixWithDisplayNameCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithDisplayNameCompositePriceFilterOperator.Includes)] + [InlineData(MatrixWithDisplayNameCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + MatrixWithDisplayNameCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + MatrixWithDisplayNameConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + MatrixWithDisplayNameConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + MatrixWithDisplayNameConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + MatrixWithDisplayNameConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameMatrixWithDisplayNameConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, model.Dimension); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, deserialized.Dimension); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } +} + +public class MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, model.DimensionValue); + Assert.Equal(expectedDisplayName, model.DisplayName); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, deserialized.DimensionValue); + Assert.Equal(expectedDisplayName, deserialized.DisplayName); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class MatrixWithDisplayNamePriceTypeTest : TestBase +{ + [Theory] + [InlineData(MatrixWithDisplayNamePriceType.UsagePrice)] + [InlineData(MatrixWithDisplayNamePriceType.FixedPrice)] + [InlineData(MatrixWithDisplayNamePriceType.CompositePrice)] + public void Validation_Works(MatrixWithDisplayNamePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MatrixWithDisplayNamePriceType.UsagePrice)] + [InlineData(MatrixWithDisplayNamePriceType.FixedPrice)] + [InlineData(MatrixWithDisplayNamePriceType.CompositePrice)] + public void SerializationRoundtrip_Works(MatrixWithDisplayNamePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedTieredPackageBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedTieredPackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedTieredPackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedTieredPackageGroupedTieredPackageConfig expectedGroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_tiered_package\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedTieredPackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedGroupedTieredPackageConfig, model.GroupedTieredPackageConfig); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + GroupedTieredPackageBillingMode.InAdvance; + ApiEnum expectedCadence = + GroupedTieredPackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + GroupedTieredPackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + GroupedTieredPackageGroupedTieredPackageConfig expectedGroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_tiered_package\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + GroupedTieredPackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedGroupedTieredPackageConfig, deserialized.GroupedTieredPackageConfig); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = GroupedTieredPackageBillingMode.InAdvance, + Cadence = GroupedTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = GroupedTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class GroupedTieredPackageBillingModeTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredPackageBillingMode.InAdvance)] + [InlineData(GroupedTieredPackageBillingMode.InArrear)] + public void Validation_Works(GroupedTieredPackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredPackageBillingMode.InAdvance)] + [InlineData(GroupedTieredPackageBillingMode.InArrear)] + public void SerializationRoundtrip_Works(GroupedTieredPackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredPackageCadence.OneTime)] + [InlineData(GroupedTieredPackageCadence.Monthly)] + [InlineData(GroupedTieredPackageCadence.Quarterly)] + [InlineData(GroupedTieredPackageCadence.SemiAnnual)] + [InlineData(GroupedTieredPackageCadence.Annual)] + [InlineData(GroupedTieredPackageCadence.Custom)] + public void Validation_Works(GroupedTieredPackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredPackageCadence.OneTime)] + [InlineData(GroupedTieredPackageCadence.Monthly)] + [InlineData(GroupedTieredPackageCadence.Quarterly)] + [InlineData(GroupedTieredPackageCadence.SemiAnnual)] + [InlineData(GroupedTieredPackageCadence.Annual)] + [InlineData(GroupedTieredPackageCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedTieredPackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredPackageCompositePriceFilter + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + GroupedTieredPackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedTieredPackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredPackageCompositePriceFilter + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredPackageCompositePriceFilter + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + GroupedTieredPackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + GroupedTieredPackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredPackageCompositePriceFilter + { + Field = GroupedTieredPackageCompositePriceFilterField.PriceID, + Operator = GroupedTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class GroupedTieredPackageCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredPackageCompositePriceFilterField.PriceID)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.ItemID)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.PriceType)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.Currency)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(GroupedTieredPackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredPackageCompositePriceFilterField.PriceID)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.ItemID)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.PriceType)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.Currency)] + [InlineData(GroupedTieredPackageCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(GroupedTieredPackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredPackageCompositePriceFilterOperator.Includes)] + [InlineData(GroupedTieredPackageCompositePriceFilterOperator.Excludes)] + public void Validation_Works(GroupedTieredPackageCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredPackageCompositePriceFilterOperator.Includes)] + [InlineData(GroupedTieredPackageCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + GroupedTieredPackageCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedTieredPackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedTieredPackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedTieredPackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedTieredPackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageGroupedTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class GroupedTieredPackageGroupedTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedTieredPackageGroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class GroupedTieredPackagePriceTypeTest : TestBase +{ + [Theory] + [InlineData(GroupedTieredPackagePriceType.UsagePrice)] + [InlineData(GroupedTieredPackagePriceType.FixedPrice)] + [InlineData(GroupedTieredPackagePriceType.CompositePrice)] + public void Validation_Works(GroupedTieredPackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedTieredPackagePriceType.UsagePrice)] + [InlineData(GroupedTieredPackagePriceType.FixedPrice)] + [InlineData(GroupedTieredPackagePriceType.CompositePrice)] + public void SerializationRoundtrip_Works(GroupedTieredPackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + MaxGroupTieredPackageBillingMode.InAdvance; + ApiEnum expectedCadence = + MaxGroupTieredPackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MaxGroupTieredPackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MaxGroupTieredPackageMaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"max_group_tiered_package\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + MaxGroupTieredPackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaxGroupTieredPackageConfig, model.MaxGroupTieredPackageConfig); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + MaxGroupTieredPackageBillingMode.InAdvance; + ApiEnum expectedCadence = + MaxGroupTieredPackageCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + MaxGroupTieredPackageConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + MaxGroupTieredPackageMaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"max_group_tiered_package\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + MaxGroupTieredPackagePriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaxGroupTieredPackageConfig, deserialized.MaxGroupTieredPackageConfig); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MaxGroupTieredPackage + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = MaxGroupTieredPackageBillingMode.InAdvance, + Cadence = MaxGroupTieredPackageCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = MaxGroupTieredPackagePriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class MaxGroupTieredPackageBillingModeTest : TestBase +{ + [Theory] + [InlineData(MaxGroupTieredPackageBillingMode.InAdvance)] + [InlineData(MaxGroupTieredPackageBillingMode.InArrear)] + public void Validation_Works(MaxGroupTieredPackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaxGroupTieredPackageBillingMode.InAdvance)] + [InlineData(MaxGroupTieredPackageBillingMode.InArrear)] + public void SerializationRoundtrip_Works(MaxGroupTieredPackageBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageCadenceTest : TestBase +{ + [Theory] + [InlineData(MaxGroupTieredPackageCadence.OneTime)] + [InlineData(MaxGroupTieredPackageCadence.Monthly)] + [InlineData(MaxGroupTieredPackageCadence.Quarterly)] + [InlineData(MaxGroupTieredPackageCadence.SemiAnnual)] + [InlineData(MaxGroupTieredPackageCadence.Annual)] + [InlineData(MaxGroupTieredPackageCadence.Custom)] + public void Validation_Works(MaxGroupTieredPackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaxGroupTieredPackageCadence.OneTime)] + [InlineData(MaxGroupTieredPackageCadence.Monthly)] + [InlineData(MaxGroupTieredPackageCadence.Quarterly)] + [InlineData(MaxGroupTieredPackageCadence.SemiAnnual)] + [InlineData(MaxGroupTieredPackageCadence.Annual)] + [InlineData(MaxGroupTieredPackageCadence.Custom)] + public void SerializationRoundtrip_Works(MaxGroupTieredPackageCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaxGroupTieredPackageCompositePriceFilter + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + MaxGroupTieredPackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MaxGroupTieredPackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaxGroupTieredPackageCompositePriceFilter + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaxGroupTieredPackageCompositePriceFilter + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + MaxGroupTieredPackageCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + MaxGroupTieredPackageCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MaxGroupTieredPackageCompositePriceFilter + { + Field = MaxGroupTieredPackageCompositePriceFilterField.PriceID, + Operator = MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class MaxGroupTieredPackageCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.PriceID)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.ItemID)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.PriceType)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.Currency)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(MaxGroupTieredPackageCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.PriceID)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.ItemID)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.PriceType)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.Currency)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + MaxGroupTieredPackageCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(MaxGroupTieredPackageCompositePriceFilterOperator.Includes)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterOperator.Excludes)] + public void Validation_Works(MaxGroupTieredPackageCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaxGroupTieredPackageCompositePriceFilterOperator.Includes)] + [InlineData(MaxGroupTieredPackageCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + MaxGroupTieredPackageCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + MaxGroupTieredPackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + MaxGroupTieredPackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + MaxGroupTieredPackageConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + MaxGroupTieredPackageConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageMaxGroupTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class MaxGroupTieredPackageMaxGroupTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new MaxGroupTieredPackageMaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class MaxGroupTieredPackagePriceTypeTest : TestBase +{ + [Theory] + [InlineData(MaxGroupTieredPackagePriceType.UsagePrice)] + [InlineData(MaxGroupTieredPackagePriceType.FixedPrice)] + [InlineData(MaxGroupTieredPackagePriceType.CompositePrice)] + public void Validation_Works(MaxGroupTieredPackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaxGroupTieredPackagePriceType.UsagePrice)] + [InlineData(MaxGroupTieredPackagePriceType.FixedPrice)] + [InlineData(MaxGroupTieredPackagePriceType.CompositePrice)] + public void SerializationRoundtrip_Works(MaxGroupTieredPackagePriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + ScalableMatrixWithUnitPricingBillingMode.InAdvance; + ApiEnum expectedCadence = + ScalableMatrixWithUnitPricingCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + ScalableMatrixWithUnitPricingConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_unit_pricing\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + ScalableMatrixWithUnitPricingPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + model.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + ScalableMatrixWithUnitPricingBillingMode.InAdvance; + ApiEnum expectedCadence = + ScalableMatrixWithUnitPricingCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + ScalableMatrixWithUnitPricingConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_unit_pricing\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + ScalableMatrixWithUnitPricingPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + deserialized.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithUnitPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithUnitPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithUnitPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithUnitPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithUnitPricingBillingModeTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithUnitPricingBillingMode.InAdvance)] + [InlineData(ScalableMatrixWithUnitPricingBillingMode.InArrear)] + public void Validation_Works(ScalableMatrixWithUnitPricingBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithUnitPricingBillingMode.InAdvance)] + [InlineData(ScalableMatrixWithUnitPricingBillingMode.InArrear)] + public void SerializationRoundtrip_Works(ScalableMatrixWithUnitPricingBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingCadenceTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithUnitPricingCadence.OneTime)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Monthly)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Quarterly)] + [InlineData(ScalableMatrixWithUnitPricingCadence.SemiAnnual)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Annual)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Custom)] + public void Validation_Works(ScalableMatrixWithUnitPricingCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithUnitPricingCadence.OneTime)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Monthly)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Quarterly)] + [InlineData(ScalableMatrixWithUnitPricingCadence.SemiAnnual)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Annual)] + [InlineData(ScalableMatrixWithUnitPricingCadence.Custom)] + public void SerializationRoundtrip_Works(ScalableMatrixWithUnitPricingCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingCompositePriceFilter + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID; + ApiEnum< + string, + ScalableMatrixWithUnitPricingCompositePriceFilterOperator + > expectedOperator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingCompositePriceFilter + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithUnitPricingCompositePriceFilter + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID; + ApiEnum< + string, + ScalableMatrixWithUnitPricingCompositePriceFilterOperator + > expectedOperator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithUnitPricingCompositePriceFilter + { + Field = ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithUnitPricingCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.ItemID)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceType)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.Currency)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(ScalableMatrixWithUnitPricingCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.ItemID)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceType)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.Currency)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + ScalableMatrixWithUnitPricingCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Excludes)] + public void Validation_Works(ScalableMatrixWithUnitPricingCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes)] + [InlineData(ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + ScalableMatrixWithUnitPricingCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ScalableMatrixWithUnitPricingConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ScalableMatrixWithUnitPricingConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ScalableMatrixWithUnitPricingConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ScalableMatrixWithUnitPricingConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingPriceTypeTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithUnitPricingPriceType.UsagePrice)] + [InlineData(ScalableMatrixWithUnitPricingPriceType.FixedPrice)] + [InlineData(ScalableMatrixWithUnitPricingPriceType.CompositePrice)] + public void Validation_Works(ScalableMatrixWithUnitPricingPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithUnitPricingPriceType.UsagePrice)] + [InlineData(ScalableMatrixWithUnitPricingPriceType.FixedPrice)] + [InlineData(ScalableMatrixWithUnitPricingPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(ScalableMatrixWithUnitPricingPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, model.UnitPrice); + Assert.Equal(expectedProrate, model.Prorate); + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, deserialized.UnitPrice); + Assert.Equal(expectedProrate, deserialized.Prorate); + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactorTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + ScalableMatrixWithTieredPricingBillingMode.InAdvance; + ApiEnum expectedCadence = + ScalableMatrixWithTieredPricingCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + ScalableMatrixWithTieredPricingConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_tiered_pricing\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + ScalableMatrixWithTieredPricingPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + model.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + ScalableMatrixWithTieredPricingBillingMode.InAdvance; + ApiEnum expectedCadence = + ScalableMatrixWithTieredPricingCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + ScalableMatrixWithTieredPricingConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_tiered_pricing\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + ScalableMatrixWithTieredPricingPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + deserialized.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithTieredPricing + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = ScalableMatrixWithTieredPricingBillingMode.InAdvance, + Cadence = ScalableMatrixWithTieredPricingCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = ScalableMatrixWithTieredPricingPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingBillingModeTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithTieredPricingBillingMode.InAdvance)] + [InlineData(ScalableMatrixWithTieredPricingBillingMode.InArrear)] + public void Validation_Works(ScalableMatrixWithTieredPricingBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithTieredPricingBillingMode.InAdvance)] + [InlineData(ScalableMatrixWithTieredPricingBillingMode.InArrear)] + public void SerializationRoundtrip_Works(ScalableMatrixWithTieredPricingBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingCadenceTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithTieredPricingCadence.OneTime)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Monthly)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Quarterly)] + [InlineData(ScalableMatrixWithTieredPricingCadence.SemiAnnual)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Annual)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Custom)] + public void Validation_Works(ScalableMatrixWithTieredPricingCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithTieredPricingCadence.OneTime)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Monthly)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Quarterly)] + [InlineData(ScalableMatrixWithTieredPricingCadence.SemiAnnual)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Annual)] + [InlineData(ScalableMatrixWithTieredPricingCadence.Custom)] + public void SerializationRoundtrip_Works(ScalableMatrixWithTieredPricingCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingCompositePriceFilter + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID; + ApiEnum< + string, + ScalableMatrixWithTieredPricingCompositePriceFilterOperator + > expectedOperator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingCompositePriceFilter + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithTieredPricingCompositePriceFilter + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID; + ApiEnum< + string, + ScalableMatrixWithTieredPricingCompositePriceFilterOperator + > expectedOperator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithTieredPricingCompositePriceFilter + { + Field = ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + Operator = ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.ItemID)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceType)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.Currency)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(ScalableMatrixWithTieredPricingCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.ItemID)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceType)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.Currency)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + ScalableMatrixWithTieredPricingCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Excludes)] + public void Validation_Works( + ScalableMatrixWithTieredPricingCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes)] + [InlineData(ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + ScalableMatrixWithTieredPricingCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ScalableMatrixWithTieredPricingConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ScalableMatrixWithTieredPricingConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ScalableMatrixWithTieredPricingConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ScalableMatrixWithTieredPricingConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingPriceTypeTest : TestBase +{ + [Theory] + [InlineData(ScalableMatrixWithTieredPricingPriceType.UsagePrice)] + [InlineData(ScalableMatrixWithTieredPricingPriceType.FixedPrice)] + [InlineData(ScalableMatrixWithTieredPricingPriceType.CompositePrice)] + public void Validation_Works(ScalableMatrixWithTieredPricingPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ScalableMatrixWithTieredPricingPriceType.UsagePrice)] + [InlineData(ScalableMatrixWithTieredPricingPriceType.FixedPrice)] + [InlineData(ScalableMatrixWithTieredPricingPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(ScalableMatrixWithTieredPricingPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactorTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedBulkTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + CumulativeGroupedBulkBillingMode.InAdvance; + ApiEnum expectedCadence = + CumulativeGroupedBulkCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + CumulativeGroupedBulkConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + CumulativeGroupedBulkCumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_bulk\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + CumulativeGroupedBulkPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCumulativeGroupedBulkConfig, model.CumulativeGroupedBulkConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + CumulativeGroupedBulkBillingMode.InAdvance; + ApiEnum expectedCadence = + CumulativeGroupedBulkCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + CumulativeGroupedBulkConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + CumulativeGroupedBulkCumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_bulk\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + CumulativeGroupedBulkPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCumulativeGroupedBulkConfig, deserialized.CumulativeGroupedBulkConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CumulativeGroupedBulk + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedBulkBillingMode.InAdvance, + Cadence = CumulativeGroupedBulkCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedBulkPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedBulkBillingModeTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedBulkBillingMode.InAdvance)] + [InlineData(CumulativeGroupedBulkBillingMode.InArrear)] + public void Validation_Works(CumulativeGroupedBulkBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedBulkBillingMode.InAdvance)] + [InlineData(CumulativeGroupedBulkBillingMode.InArrear)] + public void SerializationRoundtrip_Works(CumulativeGroupedBulkBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkCadenceTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedBulkCadence.OneTime)] + [InlineData(CumulativeGroupedBulkCadence.Monthly)] + [InlineData(CumulativeGroupedBulkCadence.Quarterly)] + [InlineData(CumulativeGroupedBulkCadence.SemiAnnual)] + [InlineData(CumulativeGroupedBulkCadence.Annual)] + [InlineData(CumulativeGroupedBulkCadence.Custom)] + public void Validation_Works(CumulativeGroupedBulkCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedBulkCadence.OneTime)] + [InlineData(CumulativeGroupedBulkCadence.Monthly)] + [InlineData(CumulativeGroupedBulkCadence.Quarterly)] + [InlineData(CumulativeGroupedBulkCadence.SemiAnnual)] + [InlineData(CumulativeGroupedBulkCadence.Annual)] + [InlineData(CumulativeGroupedBulkCadence.Custom)] + public void SerializationRoundtrip_Works(CumulativeGroupedBulkCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedBulkCompositePriceFilter + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + CumulativeGroupedBulkCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + CumulativeGroupedBulkCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedBulkCompositePriceFilter + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedBulkCompositePriceFilter + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + CumulativeGroupedBulkCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + CumulativeGroupedBulkCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedBulkCompositePriceFilter + { + Field = CumulativeGroupedBulkCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class CumulativeGroupedBulkCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.PriceID)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.ItemID)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.PriceType)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.Currency)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(CumulativeGroupedBulkCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.PriceID)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.ItemID)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.PriceType)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.Currency)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + CumulativeGroupedBulkCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedBulkCompositePriceFilterOperator.Includes)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterOperator.Excludes)] + public void Validation_Works(CumulativeGroupedBulkCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedBulkCompositePriceFilterOperator.Includes)] + [InlineData(CumulativeGroupedBulkCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + CumulativeGroupedBulkCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + CumulativeGroupedBulkConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + CumulativeGroupedBulkConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + CumulativeGroupedBulkConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + CumulativeGroupedBulkConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkCumulativeGroupedBulkConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedGroup, model.Group); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedGroup, deserialized.Group); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValueTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedBulkPriceTypeTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedBulkPriceType.UsagePrice)] + [InlineData(CumulativeGroupedBulkPriceType.FixedPrice)] + [InlineData(CumulativeGroupedBulkPriceType.CompositePrice)] + public void Validation_Works(CumulativeGroupedBulkPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedBulkPriceType.UsagePrice)] + [InlineData(CumulativeGroupedBulkPriceType.FixedPrice)] + [InlineData(CumulativeGroupedBulkPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(CumulativeGroupedBulkPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + CumulativeGroupedAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + CumulativeGroupedAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + CumulativeGroupedAllocationBillingMode.InAdvance; + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = + CumulativeGroupedAllocationPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = CumulativeGroupedAllocationBillingMode.InAdvance, + Cadence = CumulativeGroupedAllocationCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = CumulativeGroupedAllocationPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationBillingModeTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationBillingMode.InAdvance)] + [InlineData(CumulativeGroupedAllocationBillingMode.InArrear)] + public void Validation_Works(CumulativeGroupedAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationBillingMode.InAdvance)] + [InlineData(CumulativeGroupedAllocationBillingMode.InArrear)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationCompositePriceFilter + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + CumulativeGroupedAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + CumulativeGroupedAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationCompositePriceFilter + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocationCompositePriceFilter + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + CumulativeGroupedAllocationCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + CumulativeGroupedAllocationCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocationCompositePriceFilter + { + Field = CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + Operator = CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.PriceID)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.ItemID)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.PriceType)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.Currency)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(CumulativeGroupedAllocationCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.PriceID)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.ItemID)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.PriceType)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.Currency)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works( + CumulativeGroupedAllocationCompositePriceFilterField rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterOperator.Includes)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterOperator.Excludes)] + public void Validation_Works(CumulativeGroupedAllocationCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterOperator.Includes)] + [InlineData(CumulativeGroupedAllocationCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works( + CumulativeGroupedAllocationCompositePriceFilterOperator rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationPriceTypeTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationPriceType.UsagePrice)] + [InlineData(CumulativeGroupedAllocationPriceType.FixedPrice)] + [InlineData(CumulativeGroupedAllocationPriceType.CompositePrice)] + public void Validation_Works(CumulativeGroupedAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationPriceType.UsagePrice)] + [InlineData(CumulativeGroupedAllocationPriceType.FixedPrice)] + [InlineData(CumulativeGroupedAllocationPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceMinimumTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + PriceMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = PriceMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PriceMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + PriceMinimumMinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"minimum\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = PriceMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedMinimumConfig, model.MinimumConfig); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + PriceMinimumBillingMode.InAdvance; + ApiEnum expectedCadence = PriceMinimumCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PriceMinimumConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + PriceMinimumMinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"minimum\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = PriceMinimumPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedMinimumConfig, deserialized.MinimumConfig); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceMinimum + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PriceMinimumBillingMode.InAdvance, + Cadence = PriceMinimumCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + Name = "name", + PlanPhaseOrder = 0, + PriceType = PriceMinimumPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class PriceMinimumBillingModeTest : TestBase +{ + [Theory] + [InlineData(PriceMinimumBillingMode.InAdvance)] + [InlineData(PriceMinimumBillingMode.InArrear)] + public void Validation_Works(PriceMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceMinimumBillingMode.InAdvance)] + [InlineData(PriceMinimumBillingMode.InArrear)] + public void SerializationRoundtrip_Works(PriceMinimumBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceMinimumCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceMinimumCadence.OneTime)] + [InlineData(PriceMinimumCadence.Monthly)] + [InlineData(PriceMinimumCadence.Quarterly)] + [InlineData(PriceMinimumCadence.SemiAnnual)] + [InlineData(PriceMinimumCadence.Annual)] + [InlineData(PriceMinimumCadence.Custom)] + public void Validation_Works(PriceMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceMinimumCadence.OneTime)] + [InlineData(PriceMinimumCadence.Monthly)] + [InlineData(PriceMinimumCadence.Quarterly)] + [InlineData(PriceMinimumCadence.SemiAnnual)] + [InlineData(PriceMinimumCadence.Annual)] + [InlineData(PriceMinimumCadence.Custom)] + public void SerializationRoundtrip_Works(PriceMinimumCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceMinimumCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceMinimumCompositePriceFilter + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PriceMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PriceMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceMinimumCompositePriceFilter + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceMinimumCompositePriceFilter + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PriceMinimumCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PriceMinimumCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceMinimumCompositePriceFilter + { + Field = PriceMinimumCompositePriceFilterField.PriceID, + Operator = PriceMinimumCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PriceMinimumCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PriceMinimumCompositePriceFilterField.PriceID)] + [InlineData(PriceMinimumCompositePriceFilterField.ItemID)] + [InlineData(PriceMinimumCompositePriceFilterField.PriceType)] + [InlineData(PriceMinimumCompositePriceFilterField.Currency)] + [InlineData(PriceMinimumCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(PriceMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceMinimumCompositePriceFilterField.PriceID)] + [InlineData(PriceMinimumCompositePriceFilterField.ItemID)] + [InlineData(PriceMinimumCompositePriceFilterField.PriceType)] + [InlineData(PriceMinimumCompositePriceFilterField.Currency)] + [InlineData(PriceMinimumCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PriceMinimumCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceMinimumCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PriceMinimumCompositePriceFilterOperator.Includes)] + [InlineData(PriceMinimumCompositePriceFilterOperator.Excludes)] + public void Validation_Works(PriceMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceMinimumCompositePriceFilterOperator.Includes)] + [InlineData(PriceMinimumCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PriceMinimumCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceMinimumConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceMinimumConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceMinimumConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PriceMinimumMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceMinimumMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedProrated, model.Prorated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceMinimumMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceMinimumMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedProrated, deserialized.Prorated); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceMinimumMinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceMinimumMinimumConfig { MinimumAmount = "minimum_amount" }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new PriceMinimumMinimumConfig { MinimumAmount = "minimum_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new PriceMinimumMinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceMinimumMinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + model.Validate(); + } +} + +public class PriceMinimumPriceTypeTest : TestBase +{ + [Theory] + [InlineData(PriceMinimumPriceType.UsagePrice)] + [InlineData(PriceMinimumPriceType.FixedPrice)] + [InlineData(PriceMinimumPriceType.CompositePrice)] + public void Validation_Works(PriceMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceMinimumPriceType.UsagePrice)] + [InlineData(PriceMinimumPriceType.FixedPrice)] + [InlineData(PriceMinimumPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(PriceMinimumPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = PercentBillingMode.InAdvance; + ApiEnum expectedCadence = PercentCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "name"; + PercentConfig expectedPercentConfig = new(0); + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = PercentPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = PercentBillingMode.InAdvance; + ApiEnum expectedCadence = PercentCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "name"; + PercentConfig expectedPercentConfig = new(0); + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = PercentPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Percent + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = PercentBillingMode.InAdvance, + Cadence = PercentCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PercentConfig = new(0), + PlanPhaseOrder = 0, + PriceType = PercentPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class PercentBillingModeTest : TestBase +{ + [Theory] + [InlineData(PercentBillingMode.InAdvance)] + [InlineData(PercentBillingMode.InArrear)] + public void Validation_Works(PercentBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentBillingMode.InAdvance)] + [InlineData(PercentBillingMode.InArrear)] + public void SerializationRoundtrip_Works(PercentBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.Custom)] + public void Validation_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.Custom)] + public void SerializationRoundtrip_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentCompositePriceFilter + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + PercentCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PercentCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentCompositePriceFilter + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentCompositePriceFilter + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + PercentCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + PercentCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PercentCompositePriceFilter + { + Field = PercentCompositePriceFilterField.PriceID, + Operator = PercentCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class PercentCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(PercentCompositePriceFilterField.PriceID)] + [InlineData(PercentCompositePriceFilterField.ItemID)] + [InlineData(PercentCompositePriceFilterField.PriceType)] + [InlineData(PercentCompositePriceFilterField.Currency)] + [InlineData(PercentCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(PercentCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCompositePriceFilterField.PriceID)] + [InlineData(PercentCompositePriceFilterField.ItemID)] + [InlineData(PercentCompositePriceFilterField.PriceType)] + [InlineData(PercentCompositePriceFilterField.Currency)] + [InlineData(PercentCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(PercentCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(PercentCompositePriceFilterOperator.Includes)] + [InlineData(PercentCompositePriceFilterOperator.Excludes)] + public void Validation_Works(PercentCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCompositePriceFilterOperator.Includes)] + [InlineData(PercentCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(PercentCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PercentPriceTypeTest : TestBase +{ + [Theory] + [InlineData(PercentPriceType.UsagePrice)] + [InlineData(PercentPriceType.FixedPrice)] + [InlineData(PercentPriceType.CompositePrice)] + public void Validation_Works(PercentPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentPriceType.UsagePrice)] + [InlineData(PercentPriceType.FixedPrice)] + [InlineData(PercentPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(PercentPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + EventOutputBillingMode.InAdvance; + ApiEnum expectedCadence = EventOutputCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = EventOutputPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, model.BillingMode); + Assert.Equal(expectedCadence, model.Cadence); + Assert.NotNull(model.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, model.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], model.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditAllocation, model.CreditAllocation); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDiscount, model.Discount); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, model.Item); + Assert.Equal(expectedMaximum, model.Maximum); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPriceType, model.PriceType); + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + BillableMetricTiny expectedBillableMetric = new("id"); + BillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ApiEnum expectedBillingMode = + EventOutputBillingMode.InAdvance; + ApiEnum expectedCadence = EventOutputCadence.OneTime; + List expectedCompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ]; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Allocation expectedCreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }; + string expectedCurrency = "currency"; + SharedDiscount expectedDiscount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + BillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }; + ItemSlim expectedItem = new() { ID = "id", Name = "name" }; + Maximum expectedMaximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }; + string expectedMaximumAmount = "maximum_amount"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + Minimum expectedMinimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }; + string expectedMinimumAmount = "minimum_amount"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "name"; + long expectedPlanPhaseOrder = 0; + ApiEnum expectedPriceType = EventOutputPriceType.UsagePrice; + string expectedReplacesPriceID = "replaces_price_id"; + DimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedBillingMode, deserialized.BillingMode); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.NotNull(deserialized.CompositePriceFilters); + Assert.Equal(expectedCompositePriceFilters.Count, deserialized.CompositePriceFilters.Count); + for (int i = 0; i < expectedCompositePriceFilters.Count; i++) + { + Assert.Equal(expectedCompositePriceFilters[i], deserialized.CompositePriceFilters[i]); + } + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditAllocation, deserialized.CreditAllocation); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedDiscount, deserialized.Discount); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.Equal(expectedItem, deserialized.Item); + Assert.Equal(expectedMaximum, deserialized.Maximum); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPriceType, deserialized.PriceType); + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutput + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + BillingMode = EventOutputBillingMode.InAdvance, + Cadence = EventOutputCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() { Duration = 0, DurationUnit = DurationUnit.Day }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = EventOutputPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + + DimensionalPriceConfiguration = null, + }; + + model.Validate(); + } +} + +public class EventOutputBillingModeTest : TestBase +{ + [Theory] + [InlineData(EventOutputBillingMode.InAdvance)] + [InlineData(EventOutputBillingMode.InArrear)] + public void Validation_Works(EventOutputBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputBillingMode.InAdvance)] + [InlineData(EventOutputBillingMode.InArrear)] + public void SerializationRoundtrip_Works(EventOutputBillingMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.Custom)] + public void Validation_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputCompositePriceFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutputCompositePriceFilter + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + EventOutputCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + EventOutputCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutputCompositePriceFilter + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutputCompositePriceFilter + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + EventOutputCompositePriceFilterField.PriceID; + ApiEnum expectedOperator = + EventOutputCompositePriceFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutputCompositePriceFilter + { + Field = EventOutputCompositePriceFilterField.PriceID, + Operator = EventOutputCompositePriceFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class EventOutputCompositePriceFilterFieldTest : TestBase +{ + [Theory] + [InlineData(EventOutputCompositePriceFilterField.PriceID)] + [InlineData(EventOutputCompositePriceFilterField.ItemID)] + [InlineData(EventOutputCompositePriceFilterField.PriceType)] + [InlineData(EventOutputCompositePriceFilterField.Currency)] + [InlineData(EventOutputCompositePriceFilterField.PricingUnitID)] + public void Validation_Works(EventOutputCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCompositePriceFilterField.PriceID)] + [InlineData(EventOutputCompositePriceFilterField.ItemID)] + [InlineData(EventOutputCompositePriceFilterField.PriceType)] + [InlineData(EventOutputCompositePriceFilterField.Currency)] + [InlineData(EventOutputCompositePriceFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(EventOutputCompositePriceFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputCompositePriceFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(EventOutputCompositePriceFilterOperator.Includes)] + [InlineData(EventOutputCompositePriceFilterOperator.Excludes)] + public void Validation_Works(EventOutputCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCompositePriceFilterOperator.Includes)] + [InlineData(EventOutputCompositePriceFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(EventOutputCompositePriceFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + EventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + EventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class EventOutputPriceTypeTest : TestBase +{ + [Theory] + [InlineData(EventOutputPriceType.UsagePrice)] + [InlineData(EventOutputPriceType.FixedPrice)] + [InlineData(EventOutputPriceType.CompositePrice)] + public void Validation_Works(EventOutputPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputPriceType.UsagePrice)] + [InlineData(EventOutputPriceType.FixedPrice)] + [InlineData(EventOutputPriceType.CompositePrice)] + public void SerializationRoundtrip_Works(EventOutputPriceType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Prices/EvaluatePriceGroupTest.cs b/src/Orb.Tests/Models/Prices/EvaluatePriceGroupTest.cs new file mode 100644 index 00000000..c91eed98 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/EvaluatePriceGroupTest.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class EvaluatePriceGroupTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EvaluatePriceGroup + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }; + + string expectedAmount = "amount"; + List expectedGroupingValues = ["string"]; + double expectedQuantity = 0; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedGroupingValues.Count, model.GroupingValues.Count); + for (int i = 0; i < expectedGroupingValues.Count; i++) + { + Assert.Equal(expectedGroupingValues[i], model.GroupingValues[i]); + } + Assert.Equal(expectedQuantity, model.Quantity); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EvaluatePriceGroup + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EvaluatePriceGroup + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "amount"; + List expectedGroupingValues = ["string"]; + double expectedQuantity = 0; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedGroupingValues.Count, deserialized.GroupingValues.Count); + for (int i = 0; i < expectedGroupingValues.Count; i++) + { + Assert.Equal(expectedGroupingValues[i], deserialized.GroupingValues[i]); + } + Assert.Equal(expectedQuantity, deserialized.Quantity); + } + + [Fact] + public void Validation_Works() + { + var model = new EvaluatePriceGroup + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }; + + model.Validate(); + } +} + +public class GroupingValueTest : TestBase +{ + [Fact] + public void StringValidationWorks() + { + GroupingValue value = new("string"); + value.Validate(); + } + + [Fact] + public void DoubleValidationWorks() + { + GroupingValue value = new(0); + value.Validate(); + } + + [Fact] + public void BoolValidationWorks() + { + GroupingValue value = new(true); + value.Validate(); + } + + [Fact] + public void StringSerializationRoundtripWorks() + { + GroupingValue value = new("string"); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void DoubleSerializationRoundtripWorks() + { + GroupingValue value = new(0); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BoolSerializationRoundtripWorks() + { + GroupingValue value = new(true); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParamsTest.cs b/src/Orb.Tests/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParamsTest.cs new file mode 100644 index 00000000..2c7ad051 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Prices.ExternalPriceID; + +namespace Orb.Tests.Models.Prices.ExternalPriceID; + +public class ExternalPriceIDFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPriceIDFetchParams { ExternalPriceID = "external_price_id" }; + + string expectedExternalPriceID = "external_price_id"; + + Assert.Equal(expectedExternalPriceID, parameters.ExternalPriceID); + } +} diff --git a/src/Orb.Tests/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParamsTest.cs b/src/Orb.Tests/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParamsTest.cs new file mode 100644 index 00000000..27613db8 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParamsTest.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using Orb.Models.Prices.ExternalPriceID; + +namespace Orb.Tests.Models.Prices.ExternalPriceID; + +public class ExternalPriceIDUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new ExternalPriceIDUpdateParams + { + ExternalPriceID = "external_price_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedExternalPriceID = "external_price_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedExternalPriceID, parameters.ExternalPriceID); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new ExternalPriceIDUpdateParams { ExternalPriceID = "external_price_id" }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new ExternalPriceIDUpdateParams + { + ExternalPriceID = "external_price_id", + + Metadata = null, + }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceCreateParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceCreateParamsTest.cs new file mode 100644 index 00000000..567a4666 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceCreateParamsTest.cs @@ -0,0 +1,7253 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Prices; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Prices; + +public class PriceCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceCreateParams + { + Body = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + }; + + Body expectedBody = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + Assert.Equal(expectedBody, parameters.Body); + } +} + +public class BodyTest : TestBase +{ + [Fact] + public void NewFloatingUnitPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingTieredPrice() + { + Cadence = Models::NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Body value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackagePriceValidationWorks() + { + Body value = new( + new Models::NewFloatingPackagePrice() + { + Cadence = Models::NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingMatrixPrice() + { + Cadence = Models::NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingThresholdTotalAmountPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingThresholdTotalAmountPrice() + { + Cadence = Models::NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackagePriceValidationWorks() + { + Body value = new( + new Models::NewFloatingTieredPackagePrice() + { + Cadence = Models::NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithMinimumPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingTieredWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingGroupedTieredPrice() + { + Cadence = Models::NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageWithAllocationPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingPackageWithAllocationPrice() + { + Cadence = Models::NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithPercentPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingUnitWithPercentPrice() + { + Cadence = Models::NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithAllocationPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingMatrixWithAllocationPrice() + { + Cadence = Models::NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithProrationPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingTieredWithProrationPrice() + { + Cadence = Models::NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithProrationPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingUnitWithProrationPrice() + { + Cadence = Models::NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedAllocationPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingGroupedAllocationPrice() + { + Cadence = Models::NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkWithProrationPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Body value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNamePriceValidationWorks() + { + Body value = new( + new Models::NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = Models::NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredPackagePriceValidationWorks() + { + Body value = new( + new Models::NewFloatingGroupedTieredPackagePrice() + { + Cadence = Models::NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackagePriceValidationWorks() + { + Body value = new( + new Models::NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = Models::NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkPriceValidationWorks() + { + Body value = new( + new Models::NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = Models::NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Body value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMinimumCompositePriceValidationWorks() + { + Body value = new( + new Models::NewFloatingMinimumCompositePrice() + { + Cadence = Models::NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Body value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Body value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingTieredPrice() + { + Cadence = Models::NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Body value = new( + new BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackagePriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingPackagePrice() + { + Cadence = Models::NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingMatrixPrice() + { + Cadence = Models::NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingThresholdTotalAmountPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingThresholdTotalAmountPrice() + { + Cadence = Models::NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackagePriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingTieredPackagePrice() + { + Cadence = Models::NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithMinimumPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingTieredWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingGroupedTieredPrice() + { + Cadence = Models::NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageWithAllocationPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingPackageWithAllocationPrice() + { + Cadence = Models::NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithPercentPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingUnitWithPercentPrice() + { + Cadence = Models::NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithAllocationPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingMatrixWithAllocationPrice() + { + Cadence = Models::NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithProrationPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingTieredWithProrationPrice() + { + Cadence = Models::NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithProrationPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingUnitWithProrationPrice() + { + Cadence = Models::NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedAllocationPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingGroupedAllocationPrice() + { + Cadence = Models::NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkWithProrationPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Body value = new( + new GroupedWithMinMaxThresholds() + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNamePriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = Models::NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredPackagePriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingGroupedTieredPackagePrice() + { + Cadence = Models::NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackagePriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = Models::NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkPriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = Models::NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Body value = new( + new CumulativeGroupedAllocation() + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMinimumCompositePriceSerializationRoundtripWorks() + { + Body value = new( + new Models::NewFloatingMinimumCompositePrice() + { + Cadence = Models::NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Body value = new( + new Percent() + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Body value = new( + new EventOutput() + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Cadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + ConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Cadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedFilters = [new() { PropertyKey = "x", PropertyValue = "x" }]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Filter { PropertyKey = "x", PropertyValue = "x" }; + + model.Validate(); + } +} + +public class TierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Tier { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Tier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class CadenceTest : TestBase +{ + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void Validation_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Cadence.Annual)] + [InlineData(Cadence.SemiAnnual)] + [InlineData(Cadence.Monthly)] + [InlineData(Cadence.Quarterly)] + [InlineData(Cadence.OneTime)] + [InlineData(Cadence.Custom)] + public void SerializationRoundtrip_Works(Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + ConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + GroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedWithMinMaxThresholds + { + Cadence = GroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(GroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works(GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + CumulativeGroupedAllocationCadence.Annual; + CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new CumulativeGroupedAllocation + { + Cadence = CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CumulativeGroupedAllocationCadence.Annual)] + [InlineData(CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(CumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + CumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = PercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Percent + { + Cadence = PercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void Validation_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PercentCadence.Annual)] + [InlineData(PercentCadence.SemiAnnual)] + [InlineData(PercentCadence.Monthly)] + [InlineData(PercentCadence.Quarterly)] + [InlineData(PercentCadence.OneTime)] + [InlineData(PercentCadence.Custom)] + public void SerializationRoundtrip_Works(PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = EventOutputCadence.Annual; + string expectedCurrency = "currency"; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = EventOutputCadence.Annual; + string expectedCurrency = "currency"; + EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + EventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutput + { + Cadence = EventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class EventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void Validation_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(EventOutputCadence.Annual)] + [InlineData(EventOutputCadence.SemiAnnual)] + [InlineData(EventOutputCadence.Monthly)] + [InlineData(EventOutputCadence.Quarterly)] + [InlineData(EventOutputCadence.OneTime)] + [InlineData(EventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new EventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class EventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + EventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceEvaluateMultipleParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceEvaluateMultipleParamsTest.cs new file mode 100644 index 00000000..f1142a24 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceEvaluateMultipleParamsTest.cs @@ -0,0 +1,8154 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Prices; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Prices; + +public class PriceEvaluateMultipleParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceEvaluateMultipleParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + PriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ], + }; + + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + List expectedPriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ]; + + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.NotNull(parameters.PriceEvaluations); + Assert.Equal(expectedPriceEvaluations.Count, parameters.PriceEvaluations.Count); + for (int i = 0; i < expectedPriceEvaluations.Count; i++) + { + Assert.Equal(expectedPriceEvaluations[i], parameters.PriceEvaluations[i]); + } + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceEvaluateMultipleParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + Assert.Null(parameters.PriceEvaluations); + Assert.False(parameters.RawBodyData.ContainsKey("price_evaluations")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new PriceEvaluateMultipleParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + + // Null should be interpreted as omitted for these properties + PriceEvaluations = null, + }; + + Assert.Null(parameters.PriceEvaluations); + Assert.False(parameters.RawBodyData.ContainsKey("price_evaluations")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceEvaluateMultipleParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ], + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PriceEvaluateMultipleParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ], + + CustomerID = null, + ExternalCustomerID = null, + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } +} + +public class PriceEvaluationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + string expectedExternalPriceID = "external_price_id"; + string expectedFilter = "my_numeric_property > 100 AND my_other_property = 'bar'"; + List expectedGroupingKeys = + [ + "case when my_event_type = 'foo' then true else false end", + ]; + Price expectedPrice = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFilter, model.Filter); + Assert.NotNull(model.GroupingKeys); + Assert.Equal(expectedGroupingKeys.Count, model.GroupingKeys.Count); + for (int i = 0; i < expectedGroupingKeys.Count; i++) + { + Assert.Equal(expectedGroupingKeys[i], model.GroupingKeys[i]); + } + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedExternalPriceID = "external_price_id"; + string expectedFilter = "my_numeric_property > 100 AND my_other_property = 'bar'"; + List expectedGroupingKeys = + [ + "case when my_event_type = 'foo' then true else false end", + ]; + Price expectedPrice = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.NotNull(deserialized.GroupingKeys); + Assert.Equal(expectedGroupingKeys.Count, deserialized.GroupingKeys.Count); + for (int i = 0; i < expectedGroupingKeys.Count; i++) + { + Assert.Equal(expectedGroupingKeys[i], deserialized.GroupingKeys[i]); + } + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + Assert.Null(model.GroupingKeys); + Assert.False(model.RawData.ContainsKey("grouping_keys")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + + // Null should be interpreted as omitted for these properties + GroupingKeys = null, + }; + + Assert.Null(model.GroupingKeys); + Assert.False(model.RawData.ContainsKey("grouping_keys")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + + // Null should be interpreted as omitted for these properties + GroupingKeys = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + }; + + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.Filter); + Assert.False(model.RawData.ContainsKey("filter")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + + ExternalPriceID = null, + Filter = null, + Price = null, + PriceID = null, + }; + + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.Filter); + Assert.True(model.RawData.ContainsKey("filter")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + + ExternalPriceID = null, + Filter = null, + Price = null, + PriceID = null, + }; + + model.Validate(); + } +} + +public class PriceTest : TestBase +{ + [Fact] + public void NewFloatingUnitValidationWorks() + { + Price value = new( + new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredValidationWorks() + { + Price value = new( + new Models::NewFloatingTieredPrice() + { + Cadence = Models::NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkValidationWorks() + { + Price value = new( + new Models::NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Price value = new( + new PriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageValidationWorks() + { + Price value = new( + new Models::NewFloatingPackagePrice() + { + Cadence = Models::NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixValidationWorks() + { + Price value = new( + new Models::NewFloatingMatrixPrice() + { + Cadence = Models::NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingThresholdTotalAmountValidationWorks() + { + Price value = new( + new Models::NewFloatingThresholdTotalAmountPrice() + { + Cadence = Models::NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageValidationWorks() + { + Price value = new( + new Models::NewFloatingTieredPackagePrice() + { + Cadence = Models::NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithMinimumValidationWorks() + { + Price value = new( + new Models::NewFloatingTieredWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredValidationWorks() + { + Price value = new( + new Models::NewFloatingGroupedTieredPrice() + { + Cadence = Models::NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumValidationWorks() + { + Price value = new( + new Models::NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageWithAllocationValidationWorks() + { + Price value = new( + new Models::NewFloatingPackageWithAllocationPrice() + { + Cadence = Models::NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithPercentValidationWorks() + { + Price value = new( + new Models::NewFloatingUnitWithPercentPrice() + { + Cadence = Models::NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithAllocationValidationWorks() + { + Price value = new( + new Models::NewFloatingMatrixWithAllocationPrice() + { + Cadence = Models::NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithProrationValidationWorks() + { + Price value = new( + new Models::NewFloatingTieredWithProrationPrice() + { + Cadence = Models::NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithProrationValidationWorks() + { + Price value = new( + new Models::NewFloatingUnitWithProrationPrice() + { + Cadence = Models::NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedAllocationValidationWorks() + { + Price value = new( + new Models::NewFloatingGroupedAllocationPrice() + { + Cadence = Models::NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkWithProrationValidationWorks() + { + Price value = new( + new Models::NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumValidationWorks() + { + Price value = new( + new Models::NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumValidationWorks() + { + Price value = new( + new Models::NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Price value = new( + new PriceGroupedWithMinMaxThresholds() + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNameValidationWorks() + { + Price value = new( + new Models::NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = Models::NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredPackageValidationWorks() + { + Price value = new( + new Models::NewFloatingGroupedTieredPackagePrice() + { + Cadence = Models::NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackageValidationWorks() + { + Price value = new( + new Models::NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = Models::NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingValidationWorks() + { + Price value = new( + new Models::NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingValidationWorks() + { + Price value = new( + new Models::NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkValidationWorks() + { + Price value = new( + new Models::NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = Models::NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Price value = new( + new PriceCumulativeGroupedAllocation() + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMinimumCompositeValidationWorks() + { + Price value = new( + new Models::NewFloatingMinimumCompositePrice() + { + Cadence = Models::NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Price value = new( + new PricePercent() + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Price value = new( + new PriceEventOutput() + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingUnitPrice() + { + Cadence = Models::NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingTieredPrice() + { + Cadence = Models::NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Models::NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Price value = new( + new PriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingPackagePrice() + { + Cadence = Models::NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingMatrixPrice() + { + Cadence = Models::NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Models::NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingThresholdTotalAmountSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingThresholdTotalAmountPrice() + { + Cadence = Models::NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingTieredPackagePrice() + { + Cadence = Models::NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingTieredWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingGroupedTieredPrice() + { + Cadence = Models::NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = Models::NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingPackageWithAllocationPrice() + { + Cadence = Models::NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithPercentSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingUnitWithPercentPrice() + { + Cadence = Models::NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingMatrixWithAllocationPrice() + { + Cadence = Models::NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingTieredWithProrationPrice() + { + Cadence = Models::NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingUnitWithProrationPrice() + { + Cadence = Models::NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingGroupedAllocationPrice() + { + Cadence = Models::NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = Models::NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkWithProrationSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Models::NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = Models::NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = Models::NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Price value = new( + new PriceGroupedWithMinMaxThresholds() + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNameSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = Models::NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Models::NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingGroupedTieredPackagePrice() + { + Cadence = Models::NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Models::NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackageSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = Models::NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Models::NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = Models::NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = Models::NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = + Models::NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Price value = new( + new PriceCumulativeGroupedAllocation() + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMinimumCompositeSerializationRoundtripWorks() + { + Price value = new( + new Models::NewFloatingMinimumCompositePrice() + { + Cadence = Models::NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Models::NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Price value = new( + new PricePercent() + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Price value = new( + new PriceEventOutput() + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + PriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + PriceBulkWithFiltersCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + PriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + PriceBulkWithFiltersCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = PriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceBulkWithFiltersBulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class PriceBulkWithFiltersBulkWithFiltersConfigFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class PriceBulkWithFiltersBulkWithFiltersConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class PriceBulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceBulkWithFiltersCadence.Annual)] + [InlineData(PriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(PriceBulkWithFiltersCadence.Monthly)] + [InlineData(PriceBulkWithFiltersCadence.Quarterly)] + [InlineData(PriceBulkWithFiltersCadence.OneTime)] + [InlineData(PriceBulkWithFiltersCadence.Custom)] + public void Validation_Works(PriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceBulkWithFiltersCadence.Annual)] + [InlineData(PriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(PriceBulkWithFiltersCadence.Monthly)] + [InlineData(PriceBulkWithFiltersCadence.Quarterly)] + [InlineData(PriceBulkWithFiltersCadence.OneTime)] + [InlineData(PriceBulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works(PriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceBulkWithFiltersConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceBulkWithFiltersConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceGroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + PriceGroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + PriceGroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceGroupedWithMinMaxThresholds + { + Cadence = PriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceGroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(PriceGroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(PriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works(PriceGroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class PriceGroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceCumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + PriceCumulativeGroupedAllocationCadence.Annual; + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + PriceCumulativeGroupedAllocationCadence.Annual; + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceCumulativeGroupedAllocation + { + Cadence = PriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceCumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(PriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(PriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(PriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(PriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(PriceCumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(PriceCumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(PriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(PriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(PriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(PriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(PriceCumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works(PriceCumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class PriceCumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceCumulativeGroupedAllocationConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = PricePercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PricePercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = PricePercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PricePercentConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PricePercent + { + Cadence = PricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PricePercentCadence.Annual)] + [InlineData(PricePercentCadence.SemiAnnual)] + [InlineData(PricePercentCadence.Monthly)] + [InlineData(PricePercentCadence.Quarterly)] + [InlineData(PricePercentCadence.OneTime)] + [InlineData(PricePercentCadence.Custom)] + public void Validation_Works(PricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PricePercentCadence.Annual)] + [InlineData(PricePercentCadence.SemiAnnual)] + [InlineData(PricePercentCadence.Monthly)] + [InlineData(PricePercentCadence.Quarterly)] + [InlineData(PricePercentCadence.OneTime)] + [InlineData(PricePercentCadence.Custom)] + public void SerializationRoundtrip_Works(PricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PricePercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PricePercentPercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PricePercentPercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PricePercentPercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PricePercentPercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PricePercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PricePercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PricePercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PricePercentConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PricePercentConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = PriceEventOutputCadence.Annual; + string expectedCurrency = "currency"; + PriceEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = PriceEventOutputCadence.Annual; + string expectedCurrency = "currency"; + PriceEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + Models::NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEventOutputConversionRateConfig expectedConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + Models::NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + Models::NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEventOutput + { + Cadence = PriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceEventOutputCadence.Annual)] + [InlineData(PriceEventOutputCadence.SemiAnnual)] + [InlineData(PriceEventOutputCadence.Monthly)] + [InlineData(PriceEventOutputCadence.Quarterly)] + [InlineData(PriceEventOutputCadence.OneTime)] + [InlineData(PriceEventOutputCadence.Custom)] + public void Validation_Works(PriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceEventOutputCadence.Annual)] + [InlineData(PriceEventOutputCadence.SemiAnnual)] + [InlineData(PriceEventOutputCadence.Monthly)] + [InlineData(PriceEventOutputCadence.Quarterly)] + [InlineData(PriceEventOutputCadence.OneTime)] + [InlineData(PriceEventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(PriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEventOutputEventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEventOutputEventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEventOutputEventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class PriceEventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceEventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceEventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceEventOutputConversionRateConfig value = new( + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceEventOutputConversionRateConfig value = new( + new Models::SharedTieredConversionRateConfig() + { + ConversionRateType = Models::ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceEvaluateMultipleResponseTest.cs b/src/Orb.Tests/Models/Prices/PriceEvaluateMultipleResponseTest.cs new file mode 100644 index 00000000..2098ba77 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceEvaluateMultipleResponseTest.cs @@ -0,0 +1,423 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceEvaluateMultipleResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluateMultipleResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + List expectedData = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluateMultipleResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluateMultipleResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluateMultipleResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + model.Validate(); + } +} + +public class DataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + string expectedCurrency = "currency"; + List expectedPriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + long expectedInlinePriceIndex = 0; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedPriceGroups.Count, model.PriceGroups.Count); + for (int i = 0; i < expectedPriceGroups.Count; i++) + { + Assert.Equal(expectedPriceGroups[i], model.PriceGroups[i]); + } + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedInlinePriceIndex, model.InlinePriceIndex); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCurrency = "currency"; + List expectedPriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + long expectedInlinePriceIndex = 0; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedPriceGroups.Count, deserialized.PriceGroups.Count); + for (int i = 0; i < expectedPriceGroups.Count; i++) + { + Assert.Equal(expectedPriceGroups[i], deserialized.PriceGroups[i]); + } + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedInlinePriceIndex, deserialized.InlinePriceIndex); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.InlinePriceIndex); + Assert.False(model.RawData.ContainsKey("inline_price_index")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + + ExternalPriceID = null, + InlinePriceIndex = null, + PriceID = null, + }; + + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.InlinePriceIndex); + Assert.True(model.RawData.ContainsKey("inline_price_index")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Data + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + + ExternalPriceID = null, + InlinePriceIndex = null, + PriceID = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceEvaluateParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceEvaluateParamsTest.cs new file mode 100644 index 00000000..44ecdf36 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceEvaluateParamsTest.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceEvaluateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceEvaluateParams + { + PriceID = "price_id", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + }; + + string expectedPriceID = "price_id"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + string expectedFilter = "my_numeric_property > 100 AND my_other_property = 'bar'"; + List expectedGroupingKeys = + [ + "case when my_event_type = 'foo' then true else false end", + ]; + + Assert.Equal(expectedPriceID, parameters.PriceID); + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedFilter, parameters.Filter); + Assert.NotNull(parameters.GroupingKeys); + Assert.Equal(expectedGroupingKeys.Count, parameters.GroupingKeys.Count); + for (int i = 0; i < expectedGroupingKeys.Count; i++) + { + Assert.Equal(expectedGroupingKeys[i], parameters.GroupingKeys[i]); + } + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceEvaluateParams + { + PriceID = "price_id", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + }; + + Assert.Null(parameters.GroupingKeys); + Assert.False(parameters.RawBodyData.ContainsKey("grouping_keys")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new PriceEvaluateParams + { + PriceID = "price_id", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + + // Null should be interpreted as omitted for these properties + GroupingKeys = null, + }; + + Assert.Null(parameters.GroupingKeys); + Assert.False(parameters.RawBodyData.ContainsKey("grouping_keys")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceEvaluateParams + { + PriceID = "price_id", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Filter); + Assert.False(parameters.RawBodyData.ContainsKey("filter")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PriceEvaluateParams + { + PriceID = "price_id", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + + CustomerID = null, + ExternalCustomerID = null, + Filter = null, + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.Filter); + Assert.False(parameters.RawBodyData.ContainsKey("filter")); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceEvaluatePreviewEventsParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceEvaluatePreviewEventsParamsTest.cs new file mode 100644 index 00000000..07e76ec3 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceEvaluatePreviewEventsParamsTest.cs @@ -0,0 +1,8803 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceEvaluatePreviewEventsParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceEvaluatePreviewEventsParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + Events = + [ + new() + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + ExternalCustomerID = "external_customer_id", + PriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ], + }; + + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCustomerID = "customer_id"; + List expectedEvents = + [ + new() + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ]; + string expectedExternalCustomerID = "external_customer_id"; + List expectedPriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ]; + + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.NotNull(parameters.Events); + Assert.Equal(expectedEvents.Count, parameters.Events.Count); + for (int i = 0; i < expectedEvents.Count; i++) + { + Assert.Equal(expectedEvents[i], parameters.Events[i]); + } + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.NotNull(parameters.PriceEvaluations); + Assert.Equal(expectedPriceEvaluations.Count, parameters.PriceEvaluations.Count); + for (int i = 0; i < expectedPriceEvaluations.Count; i++) + { + Assert.Equal(expectedPriceEvaluations[i], parameters.PriceEvaluations[i]); + } + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceEvaluatePreviewEventsParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + Assert.Null(parameters.Events); + Assert.False(parameters.RawBodyData.ContainsKey("events")); + Assert.Null(parameters.PriceEvaluations); + Assert.False(parameters.RawBodyData.ContainsKey("price_evaluations")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new PriceEvaluatePreviewEventsParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + + // Null should be interpreted as omitted for these properties + Events = null, + PriceEvaluations = null, + }; + + Assert.Null(parameters.Events); + Assert.False(parameters.RawBodyData.ContainsKey("events")); + Assert.Null(parameters.PriceEvaluations); + Assert.False(parameters.RawBodyData.ContainsKey("price_evaluations")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceEvaluatePreviewEventsParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Events = + [ + new() + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + PriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ], + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PriceEvaluatePreviewEventsParams + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Events = + [ + new() + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + PriceEvaluations = + [ + new() + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }, + ], + + CustomerID = null, + ExternalCustomerID = null, + }; + + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + } +} + +public class EventTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string expectedEventName = "event_name"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedEventName, model.EventName); + Assert.Equal(expectedProperties.Count, model.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(model.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, model.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, model.Timestamp); + Assert.Equal(expectedCustomerID, model.CustomerID); + Assert.Equal(expectedExternalCustomerID, model.ExternalCustomerID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedEventName = "event_name"; + Dictionary expectedProperties = new() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }; + DateTimeOffset expectedTimestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"); + string expectedCustomerID = "customer_id"; + string expectedExternalCustomerID = "external_customer_id"; + + Assert.Equal(expectedEventName, deserialized.EventName); + Assert.Equal(expectedProperties.Count, deserialized.Properties.Count); + foreach (var item in expectedProperties) + { + Assert.True(deserialized.Properties.TryGetValue(item.Key, out var value)); + + Assert.True(JsonElement.DeepEquals(value, deserialized.Properties[item.Key])); + } + Assert.Equal(expectedTimestamp, deserialized.Timestamp); + Assert.Equal(expectedCustomerID, deserialized.CustomerID); + Assert.Equal(expectedExternalCustomerID, deserialized.ExternalCustomerID); + } + + [Fact] + public void Validation_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + Assert.Null(model.CustomerID); + Assert.False(model.RawData.ContainsKey("customer_id")); + Assert.Null(model.ExternalCustomerID); + Assert.False(model.RawData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + + CustomerID = null, + ExternalCustomerID = null, + }; + + Assert.Null(model.CustomerID); + Assert.True(model.RawData.ContainsKey("customer_id")); + Assert.Null(model.ExternalCustomerID); + Assert.True(model.RawData.ContainsKey("external_customer_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Event + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + + CustomerID = null, + ExternalCustomerID = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + string expectedExternalPriceID = "external_price_id"; + string expectedFilter = "my_numeric_property > 100 AND my_other_property = 'bar'"; + List expectedGroupingKeys = + [ + "case when my_event_type = 'foo' then true else false end", + ]; + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice expectedPrice = + new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFilter, model.Filter); + Assert.NotNull(model.GroupingKeys); + Assert.Equal(expectedGroupingKeys.Count, model.GroupingKeys.Count); + for (int i = 0; i < expectedGroupingKeys.Count; i++) + { + Assert.Equal(expectedGroupingKeys[i], model.GroupingKeys[i]); + } + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedExternalPriceID = "external_price_id"; + string expectedFilter = "my_numeric_property > 100 AND my_other_property = 'bar'"; + List expectedGroupingKeys = + [ + "case when my_event_type = 'foo' then true else false end", + ]; + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice expectedPrice = + new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.NotNull(deserialized.GroupingKeys); + Assert.Equal(expectedGroupingKeys.Count, deserialized.GroupingKeys.Count); + for (int i = 0; i < expectedGroupingKeys.Count; i++) + { + Assert.Equal(expectedGroupingKeys[i], deserialized.GroupingKeys[i]); + } + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + Assert.Null(model.GroupingKeys); + Assert.False(model.RawData.ContainsKey("grouping_keys")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + + // Null should be interpreted as omitted for these properties + GroupingKeys = null, + }; + + Assert.Null(model.GroupingKeys); + Assert.False(model.RawData.ContainsKey("grouping_keys")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + ExternalPriceID = "external_price_id", + Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "price_id", + + // Null should be interpreted as omitted for these properties + GroupingKeys = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + }; + + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.Filter); + Assert.False(model.RawData.ContainsKey("filter")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + + ExternalPriceID = null, + Filter = null, + Price = null, + PriceID = null, + }; + + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.Filter); + Assert.True(model.RawData.ContainsKey("filter")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluation + { + GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], + + ExternalPriceID = null, + Filter = null, + Price = null, + PriceID = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceTest : TestBase +{ + [Fact] + public void NewFloatingUnitValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredPrice() + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingPackagePrice() + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMatrixPrice() + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingThresholdTotalAmountValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingThresholdTotalAmountPrice() + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredPackagePrice() + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithMinimumValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredWithMinimumPrice() + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedTieredPrice() + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageWithAllocationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingPackageWithAllocationPrice() + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithPercentValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingUnitWithPercentPrice() + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithAllocationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMatrixWithAllocationPrice() + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithProrationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredWithProrationPrice() + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithProrationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingUnitWithProrationPrice() + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedAllocationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedAllocationPrice() + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkWithProrationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds() + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNameValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredPackageValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedTieredPackagePrice() + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackageValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation() + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMinimumCompositeValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMinimumCompositePrice() + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent() + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput() + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredPrice() + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingPackagePrice() + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMatrixPrice() + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingThresholdTotalAmountSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingThresholdTotalAmountPrice() + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredPackagePrice() + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithMinimumSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredWithMinimumPrice() + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedTieredPrice() + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageWithAllocationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingPackageWithAllocationPrice() + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithPercentSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingUnitWithPercentPrice() + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithAllocationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMatrixWithAllocationPrice() + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithProrationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingTieredWithProrationPrice() + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithProrationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingUnitWithProrationPrice() + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedAllocationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedAllocationPrice() + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkWithProrationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds() + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNameSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredPackageSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingGroupedTieredPackagePrice() + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackageSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation() + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMinimumCompositeSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new NewFloatingMinimumCompositePrice() + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent() + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice value = new( + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput() + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilterTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTierTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadenceTest + : TestBase +{ + [Theory] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual)] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.SemiAnnual + )] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Monthly)] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Quarterly + )] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.OneTime)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Custom)] + public void Validation_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual)] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.SemiAnnual + )] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Monthly)] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Quarterly + )] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.OneTime)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadenceTest + : TestBase +{ + [Theory] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.SemiAnnual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Monthly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Quarterly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.OneTime + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Custom + )] + public void Validation_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.SemiAnnual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Monthly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Quarterly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.OneTime + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Custom + )] + public void SerializationRoundtrip_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + { + Cadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadenceTest + : TestBase +{ + [Theory] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.SemiAnnual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Monthly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Quarterly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.OneTime + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Custom + )] + public void Validation_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.SemiAnnual + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Monthly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Quarterly + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.OneTime + )] + [InlineData( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Custom + )] + public void SerializationRoundtrip_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig expectedPercentConfig = + new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig expectedPercentConfig = + new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.SemiAnnual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Monthly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Quarterly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.OneTime)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Custom)] + public void Validation_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.SemiAnnual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Monthly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Quarterly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.OneTime)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Custom)] + public void SerializationRoundtrip_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig + { + Percent = 0, + }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig + { + Percent = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig + { + Percent = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig + { + Percent = 0, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual; + string expectedCurrency = "currency"; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + > expectedCadence = + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual; + string expectedCurrency = "currency"; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + { + Cadence = PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.SemiAnnual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Monthly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Quarterly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.OneTime)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Custom)] + public void Validation_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.SemiAnnual)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Monthly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Quarterly)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.OneTime)] + [InlineData(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Custom)] + public void SerializationRoundtrip_Works( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceEvaluatePreviewEventsResponseTest.cs b/src/Orb.Tests/Models/Prices/PriceEvaluatePreviewEventsResponseTest.cs new file mode 100644 index 00000000..1d81a9ba --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceEvaluatePreviewEventsResponseTest.cs @@ -0,0 +1,425 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceEvaluatePreviewEventsResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + List expectedData = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsResponse + { + Data = + [ + new() + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }, + ], + }; + + model.Validate(); + } +} + +public class PriceEvaluatePreviewEventsResponseDataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + string expectedCurrency = "currency"; + List expectedPriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + long expectedInlinePriceIndex = 0; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedPriceGroups.Count, model.PriceGroups.Count); + for (int i = 0; i < expectedPriceGroups.Count; i++) + { + Assert.Equal(expectedPriceGroups[i], model.PriceGroups[i]); + } + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedInlinePriceIndex, model.InlinePriceIndex); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCurrency = "currency"; + List expectedPriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + long expectedInlinePriceIndex = 0; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedPriceGroups.Count, deserialized.PriceGroups.Count); + for (int i = 0; i < expectedPriceGroups.Count; i++) + { + Assert.Equal(expectedPriceGroups[i], deserialized.PriceGroups[i]); + } + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedInlinePriceIndex, deserialized.InlinePriceIndex); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + ExternalPriceID = "external_price_id", + InlinePriceIndex = 0, + PriceID = "price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.InlinePriceIndex); + Assert.False(model.RawData.ContainsKey("inline_price_index")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + + ExternalPriceID = null, + InlinePriceIndex = null, + PriceID = null, + }; + + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.InlinePriceIndex); + Assert.True(model.RawData.ContainsKey("inline_price_index")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new PriceEvaluatePreviewEventsResponseData + { + Currency = "currency", + PriceGroups = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + + ExternalPriceID = null, + InlinePriceIndex = null, + PriceID = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceEvaluateResponseTest.cs b/src/Orb.Tests/Models/Prices/PriceEvaluateResponseTest.cs new file mode 100644 index 00000000..e58e681b --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceEvaluateResponseTest.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceEvaluateResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceEvaluateResponse + { + Data = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + List expectedData = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceEvaluateResponse + { + Data = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceEvaluateResponse + { + Data = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new PriceEvaluateResponse + { + Data = + [ + new() + { + Amount = "amount", + GroupingValues = ["string"], + Quantity = 0, + }, + ], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceFetchParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceFetchParamsTest.cs new file mode 100644 index 00000000..73088ddd --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceFetchParams { PriceID = "price_id" }; + + string expectedPriceID = "price_id"; + + Assert.Equal(expectedPriceID, parameters.PriceID); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceListPageResponseTest.cs b/src/Orb.Tests/Models/Prices/PriceListPageResponseTest.cs new file mode 100644 index 00000000..b05dd525 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceListPageResponseTest.cs @@ -0,0 +1,785 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models.Prices; +using Models = Orb.Models; + +namespace Orb.Tests.Models.Prices; + +public class PriceListPageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new PriceListPageResponse + { + Data = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new PriceListPageResponse + { + Data = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new PriceListPageResponse + { + Data = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ]; + Models::PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new PriceListPageResponse + { + Data = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceListParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceListParamsTest.cs new file mode 100644 index 00000000..a314f6f0 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceListParamsTest.cs @@ -0,0 +1,65 @@ +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceListParams { Cursor = "cursor", Limit = 1 }; + + string expectedCursor = "cursor"; + long expectedLimit = 1; + + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceListParams { Cursor = "cursor" }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new PriceListParams + { + Cursor = "cursor", + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceListParams { Limit = 1 }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PriceListParams + { + Limit = 1, + + Cursor = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + } +} diff --git a/src/Orb.Tests/Models/Prices/PriceUpdateParamsTest.cs b/src/Orb.Tests/Models/Prices/PriceUpdateParamsTest.cs new file mode 100644 index 00000000..61185d58 --- /dev/null +++ b/src/Orb.Tests/Models/Prices/PriceUpdateParamsTest.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using Orb.Models.Prices; + +namespace Orb.Tests.Models.Prices; + +public class PriceUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new PriceUpdateParams + { + PriceID = "price_id", + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string expectedPriceID = "price_id"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedPriceID, parameters.PriceID); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new PriceUpdateParams { PriceID = "price_id" }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new PriceUpdateParams + { + PriceID = "price_id", + + Metadata = null, + }; + + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + } +} diff --git a/src/Orb.Tests/Models/SharedCreditNoteTest.cs b/src/Orb.Tests/Models/SharedCreditNoteTest.cs new file mode 100644 index 00000000..90ab6dce --- /dev/null +++ b/src/Orb.Tests/Models/SharedCreditNoteTest.cs @@ -0,0 +1,2274 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SharedCreditNoteTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }; + + string expectedID = "id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCreditNoteNumber = "credit_note_number"; + string expectedCreditNotePdf = "credit_note_pdf"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedInvoiceID = "invoice_id"; + List expectedLineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + MaximumAmountAdjustment expectedMaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + string expectedMemo = "memo"; + string expectedMinimumAmountRefunded = "minimum_amount_refunded"; + ApiEnum expectedReason = Reason.Duplicate; + string expectedSubtotal = "subtotal"; + string expectedTotal = "total"; + ApiEnum expectedType = SharedCreditNoteType.Refund; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedDiscounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ]; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCreditNoteNumber, model.CreditNoteNumber); + Assert.Equal(expectedCreditNotePdf, model.CreditNotePdf); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedInvoiceID, model.InvoiceID); + Assert.Equal(expectedLineItems.Count, model.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], model.LineItems[i]); + } + Assert.Equal(expectedMaximumAmountAdjustment, model.MaximumAmountAdjustment); + Assert.Equal(expectedMemo, model.Memo); + Assert.Equal(expectedMinimumAmountRefunded, model.MinimumAmountRefunded); + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTotal, model.Total); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedVoidedAt, model.VoidedAt); + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCreditNoteNumber = "credit_note_number"; + string expectedCreditNotePdf = "credit_note_pdf"; + CustomerMinified expectedCustomer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }; + string expectedInvoiceID = "invoice_id"; + List expectedLineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + MaximumAmountAdjustment expectedMaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + string expectedMemo = "memo"; + string expectedMinimumAmountRefunded = "minimum_amount_refunded"; + ApiEnum expectedReason = Reason.Duplicate; + string expectedSubtotal = "subtotal"; + string expectedTotal = "total"; + ApiEnum expectedType = SharedCreditNoteType.Refund; + DateTimeOffset expectedVoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedDiscounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ]; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCreditNoteNumber, deserialized.CreditNoteNumber); + Assert.Equal(expectedCreditNotePdf, deserialized.CreditNotePdf); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedInvoiceID, deserialized.InvoiceID); + Assert.Equal(expectedLineItems.Count, deserialized.LineItems.Count); + for (int i = 0; i < expectedLineItems.Count; i++) + { + Assert.Equal(expectedLineItems[i], deserialized.LineItems[i]); + } + Assert.Equal(expectedMaximumAmountAdjustment, deserialized.MaximumAmountAdjustment); + Assert.Equal(expectedMemo, deserialized.Memo); + Assert.Equal(expectedMinimumAmountRefunded, deserialized.MinimumAmountRefunded); + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTotal, deserialized.Total); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedVoidedAt, deserialized.VoidedAt); + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + Discounts = null, + }; + + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new SharedCreditNote + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + Discounts = null, + }; + + model.Validate(); + } +} + +public class SharedCreditNoteLineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedItemID = "item_id"; + string expectedName = "name"; + double expectedQuantity = 0; + string expectedSubtotal = "subtotal"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedDiscounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ]; + DateTimeOffset expectedEndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedSubtotal, model.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, model.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], model.TaxAmounts[i]); + } + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedEndTimeExclusive, model.EndTimeExclusive); + Assert.Equal(expectedStartTimeInclusive, model.StartTimeInclusive); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmount = "amount"; + string expectedItemID = "item_id"; + string expectedName = "name"; + double expectedQuantity = 0; + string expectedSubtotal = "subtotal"; + List expectedTaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ]; + List expectedDiscounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ]; + DateTimeOffset expectedEndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedSubtotal, deserialized.Subtotal); + Assert.Equal(expectedTaxAmounts.Count, deserialized.TaxAmounts.Count); + for (int i = 0; i < expectedTaxAmounts.Count; i++) + { + Assert.Equal(expectedTaxAmounts[i], deserialized.TaxAmounts[i]); + } + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedEndTimeExclusive, deserialized.EndTimeExclusive); + Assert.Equal(expectedStartTimeInclusive, deserialized.StartTimeInclusive); + } + + [Fact] + public void Validation_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + Discounts = null, + }; + + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + Discounts = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + }; + + Assert.Null(model.EndTimeExclusive); + Assert.False(model.RawData.ContainsKey("end_time_exclusive")); + Assert.Null(model.StartTimeInclusive); + Assert.False(model.RawData.ContainsKey("start_time_inclusive")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + + EndTimeExclusive = null, + StartTimeInclusive = null, + }; + + Assert.Null(model.EndTimeExclusive); + Assert.True(model.RawData.ContainsKey("end_time_exclusive")); + Assert.Null(model.StartTimeInclusive); + Assert.True(model.RawData.ContainsKey("start_time_inclusive")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new SharedCreditNoteLineItem + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + + EndTimeExclusive = null, + StartTimeInclusive = null, + }; + + model.Validate(); + } +} + +public class DiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }; + + string expectedID = "id"; + string expectedAmountApplied = "amount_applied"; + List expectedAppliesToPriceIDs = ["string"]; + ApiEnum expectedDiscountType = + DiscountDiscountType.Percentage; + double expectedPercentageDiscount = 0; + string expectedAmountDiscount = "amount_discount"; + string expectedReason = "reason"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedAmountApplied, model.AmountApplied); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.Equal(expectedReason, model.Reason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedAmountApplied = "amount_applied"; + List expectedAppliesToPriceIDs = ["string"]; + ApiEnum expectedDiscountType = + DiscountDiscountType.Percentage; + double expectedPercentageDiscount = 0; + string expectedAmountDiscount = "amount_discount"; + string expectedReason = "reason"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedAmountApplied, deserialized.AmountApplied); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.Equal(expectedReason, deserialized.Reason); + } + + [Fact] + public void Validation_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + }; + + Assert.Null(model.AmountDiscount); + Assert.False(model.RawData.ContainsKey("amount_discount")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + + AmountDiscount = null, + Reason = null, + }; + + Assert.Null(model.AmountDiscount); + Assert.True(model.RawData.ContainsKey("amount_discount")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Discount + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = DiscountDiscountType.Percentage, + PercentageDiscount = 0, + + AmountDiscount = null, + Reason = null, + }; + + model.Validate(); + } +} + +public class DiscountDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(DiscountDiscountType.Percentage)] + [InlineData(DiscountDiscountType.Amount)] + public void Validation_Works(DiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DiscountDiscountType.Percentage)] + [InlineData(DiscountDiscountType.Amount)] + public void SerializationRoundtrip_Works(DiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class MaximumAmountAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + string expectedAmountApplied = "amount_applied"; + ApiEnum expectedDiscountType = + MaximumAmountAdjustmentDiscountType.Percentage; + double expectedPercentageDiscount = 0; + List expectedAppliesToPrices = [new() { ID = "id", Name = "name" }]; + string expectedReason = "reason"; + + Assert.Equal(expectedAmountApplied, model.AmountApplied); + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.NotNull(model.AppliesToPrices); + Assert.Equal(expectedAppliesToPrices.Count, model.AppliesToPrices.Count); + for (int i = 0; i < expectedAppliesToPrices.Count; i++) + { + Assert.Equal(expectedAppliesToPrices[i], model.AppliesToPrices[i]); + } + Assert.Equal(expectedReason, model.Reason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmountApplied = "amount_applied"; + ApiEnum expectedDiscountType = + MaximumAmountAdjustmentDiscountType.Percentage; + double expectedPercentageDiscount = 0; + List expectedAppliesToPrices = [new() { ID = "id", Name = "name" }]; + string expectedReason = "reason"; + + Assert.Equal(expectedAmountApplied, deserialized.AmountApplied); + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.NotNull(deserialized.AppliesToPrices); + Assert.Equal(expectedAppliesToPrices.Count, deserialized.AppliesToPrices.Count); + for (int i = 0; i < expectedAppliesToPrices.Count; i++) + { + Assert.Equal(expectedAppliesToPrices[i], deserialized.AppliesToPrices[i]); + } + Assert.Equal(expectedReason, deserialized.Reason); + } + + [Fact] + public void Validation_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + }; + + Assert.Null(model.AppliesToPrices); + Assert.False(model.RawData.ContainsKey("applies_to_prices")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + + AppliesToPrices = null, + Reason = null, + }; + + Assert.Null(model.AppliesToPrices); + Assert.True(model.RawData.ContainsKey("applies_to_prices")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MaximumAmountAdjustment + { + AmountApplied = "amount_applied", + DiscountType = MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + + AppliesToPrices = null, + Reason = null, + }; + + model.Validate(); + } +} + +public class MaximumAmountAdjustmentDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(MaximumAmountAdjustmentDiscountType.Percentage)] + public void Validation_Works(MaximumAmountAdjustmentDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(MaximumAmountAdjustmentDiscountType.Percentage)] + public void SerializationRoundtrip_Works(MaximumAmountAdjustmentDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class AppliesToPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AppliesToPrice { ID = "id", Name = "name" }; + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AppliesToPrice { ID = "id", Name = "name" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AppliesToPrice { ID = "id", Name = "name" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new AppliesToPrice { ID = "id", Name = "name" }; + + model.Validate(); + } +} + +public class ReasonTest : TestBase +{ + [Theory] + [InlineData(Reason.Duplicate)] + [InlineData(Reason.Fraudulent)] + [InlineData(Reason.OrderChange)] + [InlineData(Reason.ProductUnsatisfactory)] + public void Validation_Works(Reason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Reason.Duplicate)] + [InlineData(Reason.Fraudulent)] + [InlineData(Reason.OrderChange)] + [InlineData(Reason.ProductUnsatisfactory)] + public void SerializationRoundtrip_Works(Reason rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class SharedCreditNoteTypeTest : TestBase +{ + [Theory] + [InlineData(SharedCreditNoteType.Refund)] + [InlineData(SharedCreditNoteType.Adjustment)] + public void Validation_Works(SharedCreditNoteType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SharedCreditNoteType.Refund)] + [InlineData(SharedCreditNoteType.Adjustment)] + public void SerializationRoundtrip_Works(SharedCreditNoteType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class SharedCreditNoteDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + string expectedAmountApplied = "amount_applied"; + ApiEnum expectedDiscountType = + SharedCreditNoteDiscountDiscountType.Percentage; + double expectedPercentageDiscount = 0; + List expectedAppliesToPrices = + [ + new() { ID = "id", Name = "name" }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedAmountApplied, model.AmountApplied); + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.NotNull(model.AppliesToPrices); + Assert.Equal(expectedAppliesToPrices.Count, model.AppliesToPrices.Count); + for (int i = 0; i < expectedAppliesToPrices.Count; i++) + { + Assert.Equal(expectedAppliesToPrices[i], model.AppliesToPrices[i]); + } + Assert.Equal(expectedReason, model.Reason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmountApplied = "amount_applied"; + ApiEnum expectedDiscountType = + SharedCreditNoteDiscountDiscountType.Percentage; + double expectedPercentageDiscount = 0; + List expectedAppliesToPrices = + [ + new() { ID = "id", Name = "name" }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedAmountApplied, deserialized.AmountApplied); + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.NotNull(deserialized.AppliesToPrices); + Assert.Equal(expectedAppliesToPrices.Count, deserialized.AppliesToPrices.Count); + for (int i = 0; i < expectedAppliesToPrices.Count; i++) + { + Assert.Equal(expectedAppliesToPrices[i], deserialized.AppliesToPrices[i]); + } + Assert.Equal(expectedReason, deserialized.Reason); + } + + [Fact] + public void Validation_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + }; + + Assert.Null(model.AppliesToPrices); + Assert.False(model.RawData.ContainsKey("applies_to_prices")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + + AppliesToPrices = null, + Reason = null, + }; + + Assert.Null(model.AppliesToPrices); + Assert.True(model.RawData.ContainsKey("applies_to_prices")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new SharedCreditNoteDiscount + { + AmountApplied = "amount_applied", + DiscountType = SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + + AppliesToPrices = null, + Reason = null, + }; + + model.Validate(); + } +} + +public class SharedCreditNoteDiscountDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(SharedCreditNoteDiscountDiscountType.Percentage)] + public void Validation_Works(SharedCreditNoteDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SharedCreditNoteDiscountDiscountType.Percentage)] + public void SerializationRoundtrip_Works(SharedCreditNoteDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SharedCreditNoteDiscountAppliesToPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedCreditNoteDiscountAppliesToPrice { ID = "id", Name = "name" }; + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedCreditNoteDiscountAppliesToPrice { ID = "id", Name = "name" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedCreditNoteDiscountAppliesToPrice { ID = "id", Name = "name" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new SharedCreditNoteDiscountAppliesToPrice { ID = "id", Name = "name" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/SharedDiscountTest.cs b/src/Orb.Tests/Models/SharedDiscountTest.cs new file mode 100644 index 00000000..8dc291f5 --- /dev/null +++ b/src/Orb.Tests/Models/SharedDiscountTest.cs @@ -0,0 +1,213 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SharedDiscountTest : TestBase +{ + [Fact] + public void PercentageValidationWorks() + { + SharedDiscount value = new( + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void TrialValidationWorks() + { + SharedDiscount value = new( + new TrialDiscount() + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void UsageValidationWorks() + { + SharedDiscount value = new( + new UsageDiscount() + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void AmountValidationWorks() + { + SharedDiscount value = new( + new AmountDiscount() + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + value.Validate(); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + SharedDiscount value = new( + new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TrialSerializationRoundtripWorks() + { + SharedDiscount value = new( + new TrialDiscount() + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UsageSerializationRoundtripWorks() + { + SharedDiscount value = new( + new UsageDiscount() + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + SharedDiscount value = new( + new AmountDiscount() + { + AmountDiscountValue = "amount_discount", + DiscountType = DiscountType.Amount, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = AmountDiscountFilterField.PriceID, + Operator = AmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SharedTierTest.cs b/src/Orb.Tests/Models/SharedTierTest.cs new file mode 100644 index 00000000..ae5b3062 --- /dev/null +++ b/src/Orb.Tests/Models/SharedTierTest.cs @@ -0,0 +1,124 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SharedTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + double expectedFirstUnit = 0; + string expectedUnitAmount = "unit_amount"; + double expectedLastUnit = 0; + + Assert.Equal(expectedFirstUnit, model.FirstUnit); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedLastUnit, model.LastUnit); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedFirstUnit = 0; + string expectedUnitAmount = "unit_amount"; + double expectedLastUnit = 0; + + Assert.Equal(expectedFirstUnit, deserialized.FirstUnit); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedLastUnit, deserialized.LastUnit); + } + + [Fact] + public void Validation_Works() + { + var model = new SharedTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SharedTier { FirstUnit = 0, UnitAmount = "unit_amount" }; + + Assert.Null(model.LastUnit); + Assert.False(model.RawData.ContainsKey("last_unit")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new SharedTier { FirstUnit = 0, UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new SharedTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + + LastUnit = null, + }; + + Assert.Null(model.LastUnit); + Assert.True(model.RawData.ContainsKey("last_unit")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new SharedTier + { + FirstUnit = 0, + UnitAmount = "unit_amount", + + LastUnit = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/SharedTieredConversionRateConfigTest.cs b/src/Orb.Tests/Models/SharedTieredConversionRateConfigTest.cs new file mode 100644 index 00000000..04139b10 --- /dev/null +++ b/src/Orb.Tests/Models/SharedTieredConversionRateConfigTest.cs @@ -0,0 +1,182 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SharedTieredConversionRateConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedTieredConversionRateConfig + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + }; + + ApiEnum expectedConversionRateType = ConversionRateType.Tiered; + ConversionRateTieredConfig expectedTieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ); + + Assert.Equal(expectedConversionRateType, model.ConversionRateType); + Assert.Equal(expectedTieredConfig, model.TieredConfig); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedTieredConversionRateConfig + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedTieredConversionRateConfig + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedConversionRateType = ConversionRateType.Tiered; + ConversionRateTieredConfig expectedTieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ); + + Assert.Equal(expectedConversionRateType, deserialized.ConversionRateType); + Assert.Equal(expectedTieredConfig, deserialized.TieredConfig); + } + + [Fact] + public void Validation_Works() + { + var model = new SharedTieredConversionRateConfig + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + }; + + model.Validate(); + } +} + +public class ConversionRateTypeTest : TestBase +{ + [Theory] + [InlineData(ConversionRateType.Tiered)] + public void Validation_Works(ConversionRateType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ConversionRateType.Tiered)] + public void SerializationRoundtrip_Works(ConversionRateType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SharedUnitConversionRateConfigTest.cs b/src/Orb.Tests/Models/SharedUnitConversionRateConfigTest.cs new file mode 100644 index 00000000..72d6a056 --- /dev/null +++ b/src/Orb.Tests/Models/SharedUnitConversionRateConfigTest.cs @@ -0,0 +1,138 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SharedUnitConversionRateConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SharedUnitConversionRateConfig + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + + ApiEnum< + string, + SharedUnitConversionRateConfigConversionRateType + > expectedConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit; + ConversionRateUnitConfig expectedUnitConfig = new("unit_amount"); + + Assert.Equal(expectedConversionRateType, model.ConversionRateType); + Assert.Equal(expectedUnitConfig, model.UnitConfig); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SharedUnitConversionRateConfig + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SharedUnitConversionRateConfig + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum< + string, + SharedUnitConversionRateConfigConversionRateType + > expectedConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit; + ConversionRateUnitConfig expectedUnitConfig = new("unit_amount"); + + Assert.Equal(expectedConversionRateType, deserialized.ConversionRateType); + Assert.Equal(expectedUnitConfig, deserialized.UnitConfig); + } + + [Fact] + public void Validation_Works() + { + var model = new SharedUnitConversionRateConfig + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + + model.Validate(); + } +} + +public class SharedUnitConversionRateConfigConversionRateTypeTest : TestBase +{ + [Theory] + [InlineData(SharedUnitConversionRateConfigConversionRateType.Unit)] + public void Validation_Works(SharedUnitConversionRateConfigConversionRateType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SharedUnitConversionRateConfigConversionRateType.Unit)] + public void SerializationRoundtrip_Works( + SharedUnitConversionRateConfigConversionRateType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SubLineItemGroupingTest.cs b/src/Orb.Tests/Models/SubLineItemGroupingTest.cs new file mode 100644 index 00000000..04c33a2c --- /dev/null +++ b/src/Orb.Tests/Models/SubLineItemGroupingTest.cs @@ -0,0 +1,54 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SubLineItemGroupingTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubLineItemGrouping { Key = "region", Value = "west" }; + + string expectedKey = "region"; + string expectedValue = "west"; + + Assert.Equal(expectedKey, model.Key); + Assert.Equal(expectedValue, model.Value); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubLineItemGrouping { Key = "region", Value = "west" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubLineItemGrouping { Key = "region", Value = "west" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedKey = "region"; + string expectedValue = "west"; + + Assert.Equal(expectedKey, deserialized.Key); + Assert.Equal(expectedValue, deserialized.Value); + } + + [Fact] + public void Validation_Works() + { + var model = new SubLineItemGrouping { Key = "region", Value = "west" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/SubLineItemMatrixConfigTest.cs b/src/Orb.Tests/Models/SubLineItemMatrixConfigTest.cs new file mode 100644 index 00000000..0551d83b --- /dev/null +++ b/src/Orb.Tests/Models/SubLineItemMatrixConfigTest.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SubLineItemMatrixConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubLineItemMatrixConfig { DimensionValues = ["string"] }; + + List expectedDimensionValues = ["string"]; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubLineItemMatrixConfig { DimensionValues = ["string"] }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubLineItemMatrixConfig { DimensionValues = ["string"] }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedDimensionValues = ["string"]; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SubLineItemMatrixConfig { DimensionValues = ["string"] }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChangeMinifiedTest.cs b/src/Orb.Tests/Models/SubscriptionChangeMinifiedTest.cs new file mode 100644 index 00000000..eb40bf8b --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChangeMinifiedTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SubscriptionChangeMinifiedTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionChangeMinified { ID = "id" }; + + string expectedID = "id"; + + Assert.Equal(expectedID, model.ID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionChangeMinified { ID = "id" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionChangeMinified { ID = "id" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + + Assert.Equal(expectedID, deserialized.ID); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionChangeMinified { ID = "id" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/MutatedSubscriptionTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/MutatedSubscriptionTest.cs new file mode 100644 index 00000000..0d6dd34b --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/MutatedSubscriptionTest.cs @@ -0,0 +1,11864 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Orb.Models.SubscriptionChanges; +using Models = Orb.Models; +using Plans = Orb.Models.Plans; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class MutatedSubscriptionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + + string expectedID = "id"; + long expectedActivePlanPhaseOrder = 0; + List expectedAdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAutoCollection = true; + Models::BillingCycleAnchorConfiguration expectedBillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }; + long expectedBillingCycleDay = 1; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedCurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + Customer expectedCustomer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + List expectedDiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedInvoicingThreshold = "invoicing_threshold"; + List expectedMaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + List expectedMinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedName = "name"; + long expectedNetTerms = 0; + Models::SubscriptionChangeMinified expectedPendingSubscriptionChange = new("id"); + Plans::Plan expectedPlan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = Plans::TrialPeriodUnit.Days }, + Version = 0, + }; + List expectedPriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ]; + Models::CouponRedemption expectedRedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = Status.Active; + Models::SubscriptionTrialInfo expectedTrialInfo = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + Models::ChangedSubscriptionResources expectedChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedActivePlanPhaseOrder, model.ActivePlanPhaseOrder); + Assert.Equal(expectedAdjustmentIntervals.Count, model.AdjustmentIntervals.Count); + for (int i = 0; i < expectedAdjustmentIntervals.Count; i++) + { + Assert.Equal(expectedAdjustmentIntervals[i], model.AdjustmentIntervals[i]); + } + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal( + expectedBillingCycleAnchorConfiguration, + model.BillingCycleAnchorConfiguration + ); + Assert.Equal(expectedBillingCycleDay, model.BillingCycleDay); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCurrentBillingPeriodEndDate, model.CurrentBillingPeriodEndDate); + Assert.Equal(expectedCurrentBillingPeriodStartDate, model.CurrentBillingPeriodStartDate); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDefaultInvoiceMemo, model.DefaultInvoiceMemo); + Assert.Equal(expectedDiscountIntervals.Count, model.DiscountIntervals.Count); + for (int i = 0; i < expectedDiscountIntervals.Count; i++) + { + Assert.Equal(expectedDiscountIntervals[i], model.DiscountIntervals[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFixedFeeQuantitySchedule.Count, model.FixedFeeQuantitySchedule.Count); + for (int i = 0; i < expectedFixedFeeQuantitySchedule.Count; i++) + { + Assert.Equal(expectedFixedFeeQuantitySchedule[i], model.FixedFeeQuantitySchedule[i]); + } + Assert.Equal(expectedInvoicingThreshold, model.InvoicingThreshold); + Assert.Equal(expectedMaximumIntervals.Count, model.MaximumIntervals.Count); + for (int i = 0; i < expectedMaximumIntervals.Count; i++) + { + Assert.Equal(expectedMaximumIntervals[i], model.MaximumIntervals[i]); + } + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimumIntervals.Count, model.MinimumIntervals.Count); + for (int i = 0; i < expectedMinimumIntervals.Count; i++) + { + Assert.Equal(expectedMinimumIntervals[i], model.MinimumIntervals[i]); + } + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedPendingSubscriptionChange, model.PendingSubscriptionChange); + Assert.Equal(expectedPlan, model.Plan); + Assert.Equal(expectedPriceIntervals.Count, model.PriceIntervals.Count); + for (int i = 0; i < expectedPriceIntervals.Count; i++) + { + Assert.Equal(expectedPriceIntervals[i], model.PriceIntervals[i]); + } + Assert.Equal(expectedRedeemedCoupon, model.RedeemedCoupon); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTrialInfo, model.TrialInfo); + Assert.Equal(expectedChangedResources, model.ChangedResources); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + long expectedActivePlanPhaseOrder = 0; + List expectedAdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAutoCollection = true; + Models::BillingCycleAnchorConfiguration expectedBillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }; + long expectedBillingCycleDay = 1; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedCurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + Customer expectedCustomer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + List expectedDiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedInvoicingThreshold = "invoicing_threshold"; + List expectedMaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + List expectedMinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedName = "name"; + long expectedNetTerms = 0; + Models::SubscriptionChangeMinified expectedPendingSubscriptionChange = new("id"); + Plans::Plan expectedPlan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = Plans::TrialPeriodUnit.Days }, + Version = 0, + }; + List expectedPriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ]; + Models::CouponRedemption expectedRedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = Status.Active; + Models::SubscriptionTrialInfo expectedTrialInfo = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + Models::ChangedSubscriptionResources expectedChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedActivePlanPhaseOrder, deserialized.ActivePlanPhaseOrder); + Assert.Equal(expectedAdjustmentIntervals.Count, deserialized.AdjustmentIntervals.Count); + for (int i = 0; i < expectedAdjustmentIntervals.Count; i++) + { + Assert.Equal(expectedAdjustmentIntervals[i], deserialized.AdjustmentIntervals[i]); + } + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal( + expectedBillingCycleAnchorConfiguration, + deserialized.BillingCycleAnchorConfiguration + ); + Assert.Equal(expectedBillingCycleDay, deserialized.BillingCycleDay); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCurrentBillingPeriodEndDate, deserialized.CurrentBillingPeriodEndDate); + Assert.Equal( + expectedCurrentBillingPeriodStartDate, + deserialized.CurrentBillingPeriodStartDate + ); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDefaultInvoiceMemo, deserialized.DefaultInvoiceMemo); + Assert.Equal(expectedDiscountIntervals.Count, deserialized.DiscountIntervals.Count); + for (int i = 0; i < expectedDiscountIntervals.Count; i++) + { + Assert.Equal(expectedDiscountIntervals[i], deserialized.DiscountIntervals[i]); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal( + expectedFixedFeeQuantitySchedule.Count, + deserialized.FixedFeeQuantitySchedule.Count + ); + for (int i = 0; i < expectedFixedFeeQuantitySchedule.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantitySchedule[i], + deserialized.FixedFeeQuantitySchedule[i] + ); + } + Assert.Equal(expectedInvoicingThreshold, deserialized.InvoicingThreshold); + Assert.Equal(expectedMaximumIntervals.Count, deserialized.MaximumIntervals.Count); + for (int i = 0; i < expectedMaximumIntervals.Count; i++) + { + Assert.Equal(expectedMaximumIntervals[i], deserialized.MaximumIntervals[i]); + } + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimumIntervals.Count, deserialized.MinimumIntervals.Count); + for (int i = 0; i < expectedMinimumIntervals.Count; i++) + { + Assert.Equal(expectedMinimumIntervals[i], deserialized.MinimumIntervals[i]); + } + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedPendingSubscriptionChange, deserialized.PendingSubscriptionChange); + Assert.Equal(expectedPlan, deserialized.Plan); + Assert.Equal(expectedPriceIntervals.Count, deserialized.PriceIntervals.Count); + for (int i = 0; i < expectedPriceIntervals.Count; i++) + { + Assert.Equal(expectedPriceIntervals[i], deserialized.PriceIntervals[i]); + } + Assert.Equal(expectedRedeemedCoupon, deserialized.RedeemedCoupon); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTrialInfo, deserialized.TrialInfo); + Assert.Equal(expectedChangedResources, deserialized.ChangedResources); + } + + [Fact] + public void Validation_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }; + + Assert.Null(model.ChangedResources); + Assert.False(model.RawData.ContainsKey("changed_resources")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + + ChangedResources = null, + }; + + Assert.Null(model.ChangedResources); + Assert.True(model.RawData.ContainsKey("changed_resources")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new MutatedSubscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + + ChangedResources = null, + }; + + model.Validate(); + } +} + +public class DiscountIntervalTest : TestBase +{ + [Fact] + public void AmountValidationWorks() + { + DiscountInterval value = new( + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + value.Validate(); + } + + [Fact] + public void PercentageValidationWorks() + { + DiscountInterval value = new( + new Models::PercentageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::PercentageDiscountIntervalFilterField.PriceID, + Operator = Models::PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + value.Validate(); + } + + [Fact] + public void UsageValidationWorks() + { + DiscountInterval value = new( + new Models::UsageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::UsageDiscountIntervalFilterField.PriceID, + Operator = Models::UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + DiscountInterval value = new( + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + DiscountInterval value = new( + new Models::PercentageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::PercentageDiscountIntervalFilterField.PriceID, + Operator = Models::PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UsageSerializationRoundtripWorks() + { + DiscountInterval value = new( + new Models::UsageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::UsageDiscountIntervalFilterField.PriceID, + Operator = Models::UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Ended)] + [InlineData(Status.Upcoming)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Ended)] + [InlineData(Status.Upcoming)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeApplyParamsTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeApplyParamsTest.cs new file mode 100644 index 00000000..007e4d8a --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeApplyParamsTest.cs @@ -0,0 +1,88 @@ +using Orb.Models.SubscriptionChanges; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class SubscriptionChangeApplyParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionChangeApplyParams + { + SubscriptionChangeID = "subscription_change_id", + Description = "description", + MarkAsPaid = true, + PaymentExternalID = "payment_external_id", + PaymentNotes = "payment_notes", + PaymentReceivedDate = "2019-12-27", + PreviouslyCollectedAmount = "previously_collected_amount", + }; + + string expectedSubscriptionChangeID = "subscription_change_id"; + string expectedDescription = "description"; + bool expectedMarkAsPaid = true; + string expectedPaymentExternalID = "payment_external_id"; + string expectedPaymentNotes = "payment_notes"; + string expectedPaymentReceivedDate = "2019-12-27"; + string expectedPreviouslyCollectedAmount = "previously_collected_amount"; + + Assert.Equal(expectedSubscriptionChangeID, parameters.SubscriptionChangeID); + Assert.Equal(expectedDescription, parameters.Description); + Assert.Equal(expectedMarkAsPaid, parameters.MarkAsPaid); + Assert.Equal(expectedPaymentExternalID, parameters.PaymentExternalID); + Assert.Equal(expectedPaymentNotes, parameters.PaymentNotes); + Assert.Equal(expectedPaymentReceivedDate, parameters.PaymentReceivedDate); + Assert.Equal(expectedPreviouslyCollectedAmount, parameters.PreviouslyCollectedAmount); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionChangeApplyParams + { + SubscriptionChangeID = "subscription_change_id", + }; + + Assert.Null(parameters.Description); + Assert.False(parameters.RawBodyData.ContainsKey("description")); + Assert.Null(parameters.MarkAsPaid); + Assert.False(parameters.RawBodyData.ContainsKey("mark_as_paid")); + Assert.Null(parameters.PaymentExternalID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_external_id")); + Assert.Null(parameters.PaymentNotes); + Assert.False(parameters.RawBodyData.ContainsKey("payment_notes")); + Assert.Null(parameters.PaymentReceivedDate); + Assert.False(parameters.RawBodyData.ContainsKey("payment_received_date")); + Assert.Null(parameters.PreviouslyCollectedAmount); + Assert.False(parameters.RawBodyData.ContainsKey("previously_collected_amount")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionChangeApplyParams + { + SubscriptionChangeID = "subscription_change_id", + + Description = null, + MarkAsPaid = null, + PaymentExternalID = null, + PaymentNotes = null, + PaymentReceivedDate = null, + PreviouslyCollectedAmount = null, + }; + + Assert.Null(parameters.Description); + Assert.False(parameters.RawBodyData.ContainsKey("description")); + Assert.Null(parameters.MarkAsPaid); + Assert.False(parameters.RawBodyData.ContainsKey("mark_as_paid")); + Assert.Null(parameters.PaymentExternalID); + Assert.False(parameters.RawBodyData.ContainsKey("payment_external_id")); + Assert.Null(parameters.PaymentNotes); + Assert.False(parameters.RawBodyData.ContainsKey("payment_notes")); + Assert.Null(parameters.PaymentReceivedDate); + Assert.False(parameters.RawBodyData.ContainsKey("payment_received_date")); + Assert.Null(parameters.PreviouslyCollectedAmount); + Assert.False(parameters.RawBodyData.ContainsKey("previously_collected_amount")); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeApplyResponseTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeApplyResponseTest.cs new file mode 100644 index 00000000..36f216ff --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeApplyResponseTest.cs @@ -0,0 +1,15671 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Orb.Models.SubscriptionChanges; +using Models = Orb.Models; +using Plans = Orb.Models.Plans; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class SubscriptionChangeApplyResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string expectedID = "id"; + string expectedChangeType = "change_type"; + DateTimeOffset expectedExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + SubscriptionChangeApplyResponseStatus.Pending; + MutatedSubscription expectedSubscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + DateTimeOffset expectedAppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedBillingCycleAlignment = "billing_cycle_alignment"; + DateTimeOffset expectedCancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedChangeOption = "change_option"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedChangeType, model.ChangeType); + Assert.Equal(expectedExpirationTime, model.ExpirationTime); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.Equal(expectedAppliedAt, model.AppliedAt); + Assert.Equal(expectedBillingCycleAlignment, model.BillingCycleAlignment); + Assert.Equal(expectedCancelledAt, model.CancelledAt); + Assert.Equal(expectedChangeOption, model.ChangeOption); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedPlanID, model.PlanID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedChangeType = "change_type"; + DateTimeOffset expectedExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + SubscriptionChangeApplyResponseStatus.Pending; + MutatedSubscription expectedSubscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + DateTimeOffset expectedAppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedBillingCycleAlignment = "billing_cycle_alignment"; + DateTimeOffset expectedCancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedChangeOption = "change_option"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedChangeType, deserialized.ChangeType); + Assert.Equal(expectedExpirationTime, deserialized.ExpirationTime); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.Equal(expectedAppliedAt, deserialized.AppliedAt); + Assert.Equal(expectedBillingCycleAlignment, deserialized.BillingCycleAlignment); + Assert.Equal(expectedCancelledAt, deserialized.CancelledAt); + Assert.Equal(expectedChangeOption, deserialized.ChangeOption); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedPlanID, deserialized.PlanID); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + }; + + Assert.Null(model.AppliedAt); + Assert.False(model.RawData.ContainsKey("applied_at")); + Assert.Null(model.BillingCycleAlignment); + Assert.False(model.RawData.ContainsKey("billing_cycle_alignment")); + Assert.Null(model.CancelledAt); + Assert.False(model.RawData.ContainsKey("cancelled_at")); + Assert.Null(model.ChangeOption); + Assert.False(model.RawData.ContainsKey("change_option")); + Assert.Null(model.EffectiveDate); + Assert.False(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.PlanID); + Assert.False(model.RawData.ContainsKey("plan_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + + AppliedAt = null, + BillingCycleAlignment = null, + CancelledAt = null, + ChangeOption = null, + EffectiveDate = null, + PlanID = null, + }; + + Assert.Null(model.AppliedAt); + Assert.True(model.RawData.ContainsKey("applied_at")); + Assert.Null(model.BillingCycleAlignment); + Assert.True(model.RawData.ContainsKey("billing_cycle_alignment")); + Assert.Null(model.CancelledAt); + Assert.True(model.RawData.ContainsKey("cancelled_at")); + Assert.Null(model.ChangeOption); + Assert.True(model.RawData.ContainsKey("change_option")); + Assert.Null(model.EffectiveDate); + Assert.True(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.PlanID); + Assert.True(model.RawData.ContainsKey("plan_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new SubscriptionChangeApplyResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeApplyResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + + AppliedAt = null, + BillingCycleAlignment = null, + CancelledAt = null, + ChangeOption = null, + EffectiveDate = null, + PlanID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionChangeApplyResponseStatusTest : TestBase +{ + [Theory] + [InlineData(SubscriptionChangeApplyResponseStatus.Pending)] + [InlineData(SubscriptionChangeApplyResponseStatus.Applied)] + [InlineData(SubscriptionChangeApplyResponseStatus.Cancelled)] + public void Validation_Works(SubscriptionChangeApplyResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SubscriptionChangeApplyResponseStatus.Pending)] + [InlineData(SubscriptionChangeApplyResponseStatus.Applied)] + [InlineData(SubscriptionChangeApplyResponseStatus.Cancelled)] + public void SerializationRoundtrip_Works(SubscriptionChangeApplyResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeCancelParamsTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeCancelParamsTest.cs new file mode 100644 index 00000000..e6d5b407 --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeCancelParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.SubscriptionChanges; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class SubscriptionChangeCancelParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionChangeCancelParams + { + SubscriptionChangeID = "subscription_change_id", + }; + + string expectedSubscriptionChangeID = "subscription_change_id"; + + Assert.Equal(expectedSubscriptionChangeID, parameters.SubscriptionChangeID); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeCancelResponseTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeCancelResponseTest.cs new file mode 100644 index 00000000..32e09e89 --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeCancelResponseTest.cs @@ -0,0 +1,15671 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Orb.Models.SubscriptionChanges; +using Models = Orb.Models; +using Plans = Orb.Models.Plans; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class SubscriptionChangeCancelResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string expectedID = "id"; + string expectedChangeType = "change_type"; + DateTimeOffset expectedExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + SubscriptionChangeCancelResponseStatus.Pending; + MutatedSubscription expectedSubscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + DateTimeOffset expectedAppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedBillingCycleAlignment = "billing_cycle_alignment"; + DateTimeOffset expectedCancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedChangeOption = "change_option"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedChangeType, model.ChangeType); + Assert.Equal(expectedExpirationTime, model.ExpirationTime); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.Equal(expectedAppliedAt, model.AppliedAt); + Assert.Equal(expectedBillingCycleAlignment, model.BillingCycleAlignment); + Assert.Equal(expectedCancelledAt, model.CancelledAt); + Assert.Equal(expectedChangeOption, model.ChangeOption); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedPlanID, model.PlanID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedChangeType = "change_type"; + DateTimeOffset expectedExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + SubscriptionChangeCancelResponseStatus.Pending; + MutatedSubscription expectedSubscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + DateTimeOffset expectedAppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedBillingCycleAlignment = "billing_cycle_alignment"; + DateTimeOffset expectedCancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedChangeOption = "change_option"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedChangeType, deserialized.ChangeType); + Assert.Equal(expectedExpirationTime, deserialized.ExpirationTime); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.Equal(expectedAppliedAt, deserialized.AppliedAt); + Assert.Equal(expectedBillingCycleAlignment, deserialized.BillingCycleAlignment); + Assert.Equal(expectedCancelledAt, deserialized.CancelledAt); + Assert.Equal(expectedChangeOption, deserialized.ChangeOption); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedPlanID, deserialized.PlanID); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + }; + + Assert.Null(model.AppliedAt); + Assert.False(model.RawData.ContainsKey("applied_at")); + Assert.Null(model.BillingCycleAlignment); + Assert.False(model.RawData.ContainsKey("billing_cycle_alignment")); + Assert.Null(model.CancelledAt); + Assert.False(model.RawData.ContainsKey("cancelled_at")); + Assert.Null(model.ChangeOption); + Assert.False(model.RawData.ContainsKey("change_option")); + Assert.Null(model.EffectiveDate); + Assert.False(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.PlanID); + Assert.False(model.RawData.ContainsKey("plan_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + + AppliedAt = null, + BillingCycleAlignment = null, + CancelledAt = null, + ChangeOption = null, + EffectiveDate = null, + PlanID = null, + }; + + Assert.Null(model.AppliedAt); + Assert.True(model.RawData.ContainsKey("applied_at")); + Assert.Null(model.BillingCycleAlignment); + Assert.True(model.RawData.ContainsKey("billing_cycle_alignment")); + Assert.Null(model.CancelledAt); + Assert.True(model.RawData.ContainsKey("cancelled_at")); + Assert.Null(model.ChangeOption); + Assert.True(model.RawData.ContainsKey("change_option")); + Assert.Null(model.EffectiveDate); + Assert.True(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.PlanID); + Assert.True(model.RawData.ContainsKey("plan_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new SubscriptionChangeCancelResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeCancelResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + + AppliedAt = null, + BillingCycleAlignment = null, + CancelledAt = null, + ChangeOption = null, + EffectiveDate = null, + PlanID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionChangeCancelResponseStatusTest : TestBase +{ + [Theory] + [InlineData(SubscriptionChangeCancelResponseStatus.Pending)] + [InlineData(SubscriptionChangeCancelResponseStatus.Applied)] + [InlineData(SubscriptionChangeCancelResponseStatus.Cancelled)] + public void Validation_Works(SubscriptionChangeCancelResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SubscriptionChangeCancelResponseStatus.Pending)] + [InlineData(SubscriptionChangeCancelResponseStatus.Applied)] + [InlineData(SubscriptionChangeCancelResponseStatus.Cancelled)] + public void SerializationRoundtrip_Works(SubscriptionChangeCancelResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeRetrieveParamsTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeRetrieveParamsTest.cs new file mode 100644 index 00000000..8f86e174 --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeRetrieveParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.SubscriptionChanges; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class SubscriptionChangeRetrieveParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionChangeRetrieveParams + { + SubscriptionChangeID = "subscription_change_id", + }; + + string expectedSubscriptionChangeID = "subscription_change_id"; + + Assert.Equal(expectedSubscriptionChangeID, parameters.SubscriptionChangeID); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponseTest.cs b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponseTest.cs new file mode 100644 index 00000000..8b9a70b1 --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponseTest.cs @@ -0,0 +1,15671 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Orb.Models.SubscriptionChanges; +using Models = Orb.Models; +using Plans = Orb.Models.Plans; + +namespace Orb.Tests.Models.SubscriptionChanges; + +public class SubscriptionChangeRetrieveResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string expectedID = "id"; + string expectedChangeType = "change_type"; + DateTimeOffset expectedExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + SubscriptionChangeRetrieveResponseStatus.Pending; + MutatedSubscription expectedSubscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + DateTimeOffset expectedAppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedBillingCycleAlignment = "billing_cycle_alignment"; + DateTimeOffset expectedCancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedChangeOption = "change_option"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedChangeType, model.ChangeType); + Assert.Equal(expectedExpirationTime, model.ExpirationTime); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedSubscription, model.Subscription); + Assert.Equal(expectedAppliedAt, model.AppliedAt); + Assert.Equal(expectedBillingCycleAlignment, model.BillingCycleAlignment); + Assert.Equal(expectedCancelledAt, model.CancelledAt); + Assert.Equal(expectedChangeOption, model.ChangeOption); + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedPlanID, model.PlanID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedChangeType = "change_type"; + DateTimeOffset expectedExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = + SubscriptionChangeRetrieveResponseStatus.Pending; + MutatedSubscription expectedSubscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }; + DateTimeOffset expectedAppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedBillingCycleAlignment = "billing_cycle_alignment"; + DateTimeOffset expectedCancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedChangeOption = "change_option"; + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedPlanID = "plan_id"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedChangeType, deserialized.ChangeType); + Assert.Equal(expectedExpirationTime, deserialized.ExpirationTime); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedSubscription, deserialized.Subscription); + Assert.Equal(expectedAppliedAt, deserialized.AppliedAt); + Assert.Equal(expectedBillingCycleAlignment, deserialized.BillingCycleAlignment); + Assert.Equal(expectedCancelledAt, deserialized.CancelledAt); + Assert.Equal(expectedChangeOption, deserialized.ChangeOption); + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedPlanID, deserialized.PlanID); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + AppliedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + BillingCycleAlignment = "billing_cycle_alignment", + CancelledAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ChangeOption = "change_option", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanID = "plan_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + }; + + Assert.Null(model.AppliedAt); + Assert.False(model.RawData.ContainsKey("applied_at")); + Assert.Null(model.BillingCycleAlignment); + Assert.False(model.RawData.ContainsKey("billing_cycle_alignment")); + Assert.Null(model.CancelledAt); + Assert.False(model.RawData.ContainsKey("cancelled_at")); + Assert.Null(model.ChangeOption); + Assert.False(model.RawData.ContainsKey("change_option")); + Assert.Null(model.EffectiveDate); + Assert.False(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.PlanID); + Assert.False(model.RawData.ContainsKey("plan_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + + AppliedAt = null, + BillingCycleAlignment = null, + CancelledAt = null, + ChangeOption = null, + EffectiveDate = null, + PlanID = null, + }; + + Assert.Null(model.AppliedAt); + Assert.True(model.RawData.ContainsKey("applied_at")); + Assert.Null(model.BillingCycleAlignment); + Assert.True(model.RawData.ContainsKey("billing_cycle_alignment")); + Assert.Null(model.CancelledAt); + Assert.True(model.RawData.ContainsKey("cancelled_at")); + Assert.Null(model.ChangeOption); + Assert.True(model.RawData.ContainsKey("change_option")); + Assert.Null(model.EffectiveDate); + Assert.True(model.RawData.ContainsKey("effective_date")); + Assert.Null(model.PlanID); + Assert.True(model.RawData.ContainsKey("plan_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new SubscriptionChangeRetrieveResponse + { + ID = "id", + ChangeType = "change_type", + ExpirationTime = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionChangeRetrieveResponseStatus.Pending, + Subscription = new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new Models::AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = Models::AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::AmountDiscountIntervalFilterField.PriceID, + Operator = Models::AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MaximumIntervalFilterField.PriceID, + Operator = Models::MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Models::MinimumIntervalFilterField.PriceID, + Operator = Models::MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new Models::PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = Status.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + ChangedResources = new() + { + CreatedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + CreatedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = Models::Action.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::Type.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceSource.Subscription, + IsPayableNow = true, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = Models::PaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::Status.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + VoidedCreditNotes = + [ + new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditNoteNumber = "credit_note_number", + CreditNotePdf = "credit_note_pdf", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + InvoiceID = "invoice_id", + LineItems = + [ + new() + { + ID = "id", + Amount = "amount", + ItemID = "item_id", + Name = "name", + Quantity = 0, + Subtotal = "subtotal", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + Discounts = + [ + new() + { + ID = "id", + AmountApplied = "amount_applied", + AppliesToPriceIDs = ["string"], + DiscountType = Models::DiscountDiscountType.Percentage, + PercentageDiscount = 0, + AmountDiscount = "amount_discount", + Reason = "reason", + }, + ], + EndTimeExclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + StartTimeInclusive = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + ], + MaximumAmountAdjustment = new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::MaximumAmountAdjustmentDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + Memo = "memo", + MinimumAmountRefunded = "minimum_amount_refunded", + Reason = Models::Reason.Duplicate, + Subtotal = "subtotal", + Total = "total", + Type = Models::SharedCreditNoteType.Refund, + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Discounts = + [ + new() + { + AmountApplied = "amount_applied", + DiscountType = + Models::SharedCreditNoteDiscountDiscountType.Percentage, + PercentageDiscount = 0, + AppliesToPrices = [new() { ID = "id", Name = "name" }], + Reason = "reason", + }, + ], + }, + ], + VoidedInvoices = + [ + new() + { + ID = "id", + AmountDue = "8.00", + AutoCollection = new() + { + Enabled = true, + NextAttemptAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + NumAttempts = 0, + PreviouslyAttemptedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + }, + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNotes = + [ + new() + { + ID = "id", + CreditNoteNumber = "credit_note_number", + Memo = "memo", + Reason = "reason", + Total = "total", + Type = "type", + VoidedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + }, + ], + Currency = "USD", + Customer = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + CustomerBalanceTransactions = + [ + new() + { + ID = "cgZa3SXcsPTVyC4Y", + Action = + Models::InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + Amount = "11.00", + CreatedAt = DateTimeOffset.Parse("2022-05-01T07:01:31+00:00"), + CreditNote = new("id"), + Description = "An optional description", + EndingBalance = "22.00", + Invoice = new("gXcsPTVyC4YZa3Sc"), + StartingBalance = "33.00", + Type = Models::InvoiceCustomerBalanceTransactionType.Increment, + }, + ], + CustomerTaxID = new() + { + Country = Models::Country.Ad, + Type = Models::CustomerTaxIDType.AdNrt, + Value = "value", + }, + Discount = JsonSerializer.Deserialize("{}"), + Discounts = + [ + new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ], + DueDate = DateTimeOffset.Parse("2022-05-30T07:00:00+00:00"), + EligibleToIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + HostedInvoiceURL = "hosted_invoice_url", + InvoiceDate = DateTimeOffset.Parse("2022-05-01T07:00:00+00:00"), + InvoiceNumber = "JYEFHK-00001", + InvoicePdf = + "https://assets.withorb.com/invoice/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + InvoiceSource = Models::InvoiceInvoiceSource.Subscription, + IssueFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + IssuedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + ID = "id", + AdjustedSubtotal = "5.00", + Adjustments = + [ + new Models::MonetaryUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + Models::MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + Amount = "amount", + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = + Models::MonetaryUsageDiscountAdjustmentFilterField.PriceID, + Operator = + Models::MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + Amount = "7.00", + CreditsApplied = "6.00", + EndDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + Filter = "filter", + Grouping = "grouping", + Name = "Fixed Fee", + PartiallyInvoicedAmount = "4.00", + Price = new Models::Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + BillingMode = Models::BillingMode.InAdvance, + Cadence = Models::UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = Models::CompositePriceFilterField.PriceID, + Operator = + Models::CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = + new Models::SharedUnitConversionRateConfig() + { + ConversionRateType = + Models::SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = + Models::CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Models::Field.PriceID, + Operator = Models::Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new Models::PercentageDiscount() + { + DiscountType = + Models::PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = + [ + "h74gfhdjvn7ujokd", + "7hfgtgjnbvc3ujkl", + ], + Filters = + [ + new() + { + Field = + Models::PercentageDiscountFilterField.PriceID, + Operator = + Models::PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = Models::DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = + Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() + { + { "foo", "string" }, + }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = + Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = Models::UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() + { + UnitAmount = "unit_amount", + Prorated = true, + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + Quantity = 1, + StartDate = DateTimeOffset.Parse("2022-02-01T08:00:00+00:00"), + SubLineItems = + [ + new Models::MatrixSubLineItem() + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + MatrixConfig = new(["string"]), + Name = "Tier One", + Quantity = 5, + Type = Models::MatrixSubLineItemType.Matrix, + ScaledQuantity = 0, + }, + ], + Subtotal = "9.00", + TaxAmounts = + [ + new() + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }, + ], + UsageCustomerIDs = ["string"], + }, + ], + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MaximumFilterField.PriceID, + Operator = Models::MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Memo = "memo", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = Models::MinimumFilterField.PriceID, + Operator = Models::MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + PaidAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentAttempts = + [ + new() + { + ID = "id", + Amount = "amount", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentProvider = + Models::InvoicePaymentAttemptPaymentProvider.Stripe, + PaymentProviderID = "payment_provider_id", + ReceiptPdf = + "https://assets.withorb.com/receipt/rUHdhmg45vY45DX/qEAeuYePaphGMdFb", + Succeeded = true, + }, + ], + PaymentFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PaymentStartedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ScheduledIssueAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + Status = Models::InvoiceStatus.Issued, + Subscription = new("VDGsT23osdLb84KD"), + Subtotal = "8.00", + SyncFailedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "8.00", + VoidedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + WillAutoIssue = true, + }, + ], + }, + }, + + AppliedAt = null, + BillingCycleAlignment = null, + CancelledAt = null, + ChangeOption = null, + EffectiveDate = null, + PlanID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionChangeRetrieveResponseStatusTest : TestBase +{ + [Theory] + [InlineData(SubscriptionChangeRetrieveResponseStatus.Pending)] + [InlineData(SubscriptionChangeRetrieveResponseStatus.Applied)] + [InlineData(SubscriptionChangeRetrieveResponseStatus.Cancelled)] + public void Validation_Works(SubscriptionChangeRetrieveResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SubscriptionChangeRetrieveResponseStatus.Pending)] + [InlineData(SubscriptionChangeRetrieveResponseStatus.Applied)] + [InlineData(SubscriptionChangeRetrieveResponseStatus.Cancelled)] + public void SerializationRoundtrip_Works(SubscriptionChangeRetrieveResponseStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionMinifiedTest.cs b/src/Orb.Tests/Models/SubscriptionMinifiedTest.cs new file mode 100644 index 00000000..5180e4f0 --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionMinifiedTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SubscriptionMinifiedTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionMinified { ID = "VDGsT23osdLb84KD" }; + + string expectedID = "VDGsT23osdLb84KD"; + + Assert.Equal(expectedID, model.ID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionMinified { ID = "VDGsT23osdLb84KD" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionMinified { ID = "VDGsT23osdLb84KD" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "VDGsT23osdLb84KD"; + + Assert.Equal(expectedID, deserialized.ID); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionMinified { ID = "VDGsT23osdLb84KD" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/SubscriptionTrialInfoTest.cs b/src/Orb.Tests/Models/SubscriptionTrialInfoTest.cs new file mode 100644 index 00000000..c80e4695 --- /dev/null +++ b/src/Orb.Tests/Models/SubscriptionTrialInfoTest.cs @@ -0,0 +1,63 @@ +using System; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class SubscriptionTrialInfoTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionTrialInfo + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedEndDate, model.EndDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionTrialInfo + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionTrialInfo + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedEndDate, deserialized.EndDate); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionTrialInfo + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/DiscountOverrideTest.cs b/src/Orb.Tests/Models/Subscriptions/DiscountOverrideTest.cs new file mode 100644 index 00000000..836b4015 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/DiscountOverrideTest.cs @@ -0,0 +1,204 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class DiscountOverrideTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DiscountOverride + { + DiscountType = DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }; + + ApiEnum expectedDiscountType = DiscountType.Percentage; + string expectedAmountDiscount = "amount_discount"; + double expectedPercentageDiscount = 0.15; + double expectedUsageDiscount = 0; + + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + Assert.Equal(expectedUsageDiscount, model.UsageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DiscountOverride + { + DiscountType = DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DiscountOverride + { + DiscountType = DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedDiscountType = DiscountType.Percentage; + string expectedAmountDiscount = "amount_discount"; + double expectedPercentageDiscount = 0.15; + double expectedUsageDiscount = 0; + + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + Assert.Equal(expectedUsageDiscount, deserialized.UsageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new DiscountOverride + { + DiscountType = DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new DiscountOverride { DiscountType = DiscountType.Percentage }; + + Assert.Null(model.AmountDiscount); + Assert.False(model.RawData.ContainsKey("amount_discount")); + Assert.Null(model.PercentageDiscount); + Assert.False(model.RawData.ContainsKey("percentage_discount")); + Assert.Null(model.UsageDiscount); + Assert.False(model.RawData.ContainsKey("usage_discount")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new DiscountOverride { DiscountType = DiscountType.Percentage }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new DiscountOverride + { + DiscountType = DiscountType.Percentage, + + AmountDiscount = null, + PercentageDiscount = null, + UsageDiscount = null, + }; + + Assert.Null(model.AmountDiscount); + Assert.True(model.RawData.ContainsKey("amount_discount")); + Assert.Null(model.PercentageDiscount); + Assert.True(model.RawData.ContainsKey("percentage_discount")); + Assert.Null(model.UsageDiscount); + Assert.True(model.RawData.ContainsKey("usage_discount")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new DiscountOverride + { + DiscountType = DiscountType.Percentage, + + AmountDiscount = null, + PercentageDiscount = null, + UsageDiscount = null, + }; + + model.Validate(); + } +} + +public class DiscountTypeTest : TestBase +{ + [Theory] + [InlineData(DiscountType.Percentage)] + [InlineData(DiscountType.Usage)] + [InlineData(DiscountType.Amount)] + public void Validation_Works(DiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DiscountType.Percentage)] + [InlineData(DiscountType.Usage)] + [InlineData(DiscountType.Amount)] + public void SerializationRoundtrip_Works(DiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionBulkPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionBulkPriceTest.cs new file mode 100644 index 00000000..3db896ad --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionBulkPriceTest.cs @@ -0,0 +1,682 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionBulkPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionBulkPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = Subscriptions::ModelType.Bulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkConfig, model.BulkConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + BulkConfig expectedBulkConfig = new( + [new() { UnitAmount = "unit_amount", MaximumUnits = 0 }] + ); + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionBulkPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = Subscriptions::ModelType.Bulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkConfig, deserialized.BulkConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionBulkPrice + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionBulkPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Custom)] + public void Validation_Works(Subscriptions::NewSubscriptionBulkPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionBulkPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionBulkPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ModelType.Bulk)] + public void Validation_Works(Subscriptions::ModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ModelType.Bulk)] + public void SerializationRoundtrip_Works(Subscriptions::ModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionBulkPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceTest.cs new file mode 100644 index 00000000..ea932432 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceTest.cs @@ -0,0 +1,966 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionBulkWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Subscriptions::BulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum< + string, + Subscriptions::NewSubscriptionBulkWithProrationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionBulkWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithProrationConfig, model.BulkWithProrationConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::BulkWithProrationConfig expectedBulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ); + ApiEnum< + string, + Subscriptions::NewSubscriptionBulkWithProrationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionBulkWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithProrationConfig, deserialized.BulkWithProrationConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionBulkWithProrationPrice + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class BulkWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::BulkWithProrationConfig + { + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class BulkWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::BulkWithProrationConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionBulkWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionBulkWithProrationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionBulkWithProrationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionBulkWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration)] + public void Validation_Works( + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionBulkWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionBulkWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionBulkWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionBulkWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionBulkWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceTest.cs new file mode 100644 index 00000000..69fc676c --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceTest.cs @@ -0,0 +1,1036 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionCumulativeGroupedBulkPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual; + Subscriptions::CumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCumulativeGroupedBulkConfig, model.CumulativeGroupedBulkConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual; + Subscriptions::CumulativeGroupedBulkConfig expectedCumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCumulativeGroupedBulkConfig, deserialized.CumulativeGroupedBulkConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionCumulativeGroupedBulkPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedBulkConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, model.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], model.DimensionValues[i]); + } + Assert.Equal(expectedGroup, model.Group); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedDimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + string expectedGroup = "group"; + + Assert.Equal(expectedDimensionValues.Count, deserialized.DimensionValues.Count); + for (int i = 0; i < expectedDimensionValues.Count; i++) + { + Assert.Equal(expectedDimensionValues[i], deserialized.DimensionValues[i]); + } + Assert.Equal(expectedGroup, deserialized.Group); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::CumulativeGroupedBulkConfig + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }; + + model.Validate(); + } +} + +public class DimensionValueTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::DimensionValue + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionCumulativeGroupedBulkPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk + )] + public void Validation_Works( + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceTest.cs new file mode 100644 index 00000000..9c79896b --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceTest.cs @@ -0,0 +1,836 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionGroupedAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedAllocationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual; + Subscriptions::GroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedGroupedAllocationConfig, model.GroupedAllocationConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedAllocationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual; + Subscriptions::GroupedAllocationConfig expectedGroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedGroupedAllocationConfig, deserialized.GroupedAllocationConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedAllocationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedAllocationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedOverageUnitRate, model.OverageUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedGroupingKey = "x"; + string expectedOverageUnitRate = "overage_unit_rate"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedOverageUnitRate, deserialized.OverageUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedAllocationConfig + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation)] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionGroupedAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionGroupedAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionGroupedAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceTest.cs new file mode 100644 index 00000000..b00d78f4 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceTest.cs @@ -0,0 +1,984 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionGroupedTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual; + Subscriptions::GroupedTieredPackageConfig expectedGroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedGroupedTieredPackageConfig, model.GroupedTieredPackageConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual; + Subscriptions::GroupedTieredPackageConfig expectedGroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedGroupedTieredPackageConfig, deserialized.GroupedTieredPackageConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class GroupedTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedTieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage + )] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionGroupedTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedTieredPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedTieredPriceTest.cs new file mode 100644 index 00000000..eb941d24 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedTieredPriceTest.cs @@ -0,0 +1,934 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionGroupedTieredPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual; + Subscriptions::GroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedTieredPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedGroupedTieredConfig, model.GroupedTieredConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual; + Subscriptions::GroupedTieredConfig expectedGroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedTieredPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedGroupedTieredConfig, deserialized.GroupedTieredConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedTieredPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedTieredPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Custom)] + public void Validation_Works(Subscriptions::NewSubscriptionGroupedTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedTieredPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedTieredConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedTieredConfig + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class GroupedTieredConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedTieredConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedTieredPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered)] + public void Validation_Works(Subscriptions::NewSubscriptionGroupedTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedTieredPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionGroupedTieredPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceTest.cs new file mode 100644 index 00000000..7f544a31 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceTest.cs @@ -0,0 +1,1158 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionGroupedWithMeteredMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual; + Subscriptions::GroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = + new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + model.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual; + Subscriptions::GroupedWithMeteredMinimumConfig expectedGroupedWithMeteredMinimumConfig = + new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMeteredMinimumConfig, + deserialized.GroupedWithMeteredMinimumConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedWithMeteredMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMeteredMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, model.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, model.PricingKey); + Assert.Equal(expectedScalingFactors.Count, model.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], model.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, model.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimumUnitAmount = "minimum_unit_amount"; + string expectedPricingKey = "pricing_key"; + List expectedScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ]; + string expectedScalingKey = "scaling_key"; + List expectedUnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimumUnitAmount, deserialized.MinimumUnitAmount); + Assert.Equal(expectedPricingKey, deserialized.PricingKey); + Assert.Equal(expectedScalingFactors.Count, deserialized.ScalingFactors.Count); + for (int i = 0; i < expectedScalingFactors.Count; i++) + { + Assert.Equal(expectedScalingFactors[i], deserialized.ScalingFactors[i]); + } + Assert.Equal(expectedScalingKey, deserialized.ScalingKey); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedWithMeteredMinimumConfig + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() { ScalingFactorValue = "scaling_factor", ScalingValue = "scaling_value" }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class ScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string expectedScalingFactorValue = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactorValue, model.ScalingFactorValue); + Assert.Equal(expectedScalingValue, model.ScalingValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedScalingFactorValue = "scaling_factor"; + string expectedScalingValue = "scaling_value"; + + Assert.Equal(expectedScalingFactorValue, deserialized.ScalingFactorValue); + Assert.Equal(expectedScalingValue, deserialized.ScalingValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ScalingFactor + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }; + + model.Validate(); + } +} + +public class UnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmountValue = "unit_amount"; + + Assert.Equal(expectedPricingValue, model.PricingValue); + Assert.Equal(expectedUnitAmountValue, model.UnitAmountValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPricingValue = "pricing_value"; + string expectedUnitAmountValue = "unit_amount"; + + Assert.Equal(expectedPricingValue, deserialized.PricingValue); + Assert.Equal(expectedUnitAmountValue, deserialized.UnitAmountValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::UnitAmount + { + PricingValue = "pricing_value", + UnitAmountValue = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedWithMeteredMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum + )] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceTest.cs new file mode 100644 index 00000000..f04de4b3 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceTest.cs @@ -0,0 +1,864 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionGroupedWithProratedMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual; + Subscriptions::GroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = + new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + model.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual; + Subscriptions::GroupedWithProratedMinimumConfig expectedGroupedWithProratedMinimumConfig = + new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithProratedMinimumConfig, + deserialized.GroupedWithProratedMinimumConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedWithProratedMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithProratedMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMinimum, model.Minimum); + Assert.Equal(expectedUnitRate, model.UnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMinimum = "minimum"; + string expectedUnitRate = "unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMinimum, deserialized.Minimum); + Assert.Equal(expectedUnitRate, deserialized.UnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedWithProratedMinimumConfig + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }; + + model.Validate(); + } +} + +public class NewSubscriptionGroupedWithProratedMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum + )] + public void Validation_Works( + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixPriceTest.cs new file mode 100644 index 00000000..7ade130b --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixPriceTest.cs @@ -0,0 +1,718 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionMatrixPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewSubscriptionMatrixPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewSubscriptionMatrixPriceModelType.Matrix; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionMatrixPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixConfig, model.MatrixConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewSubscriptionMatrixPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixConfig expectedMatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewSubscriptionMatrixPriceModelType.Matrix; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionMatrixPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixConfig, deserialized.MatrixConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewSubscriptionMatrixPrice + { + Cadence = NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionMatrixPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionMatrixPriceCadence.Annual)] + [InlineData(NewSubscriptionMatrixPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionMatrixPriceCadence.Monthly)] + [InlineData(NewSubscriptionMatrixPriceCadence.Quarterly)] + [InlineData(NewSubscriptionMatrixPriceCadence.OneTime)] + [InlineData(NewSubscriptionMatrixPriceCadence.Custom)] + public void Validation_Works(NewSubscriptionMatrixPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionMatrixPriceCadence.Annual)] + [InlineData(NewSubscriptionMatrixPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionMatrixPriceCadence.Monthly)] + [InlineData(NewSubscriptionMatrixPriceCadence.Quarterly)] + [InlineData(NewSubscriptionMatrixPriceCadence.OneTime)] + [InlineData(NewSubscriptionMatrixPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewSubscriptionMatrixPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMatrixPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionMatrixPriceModelType.Matrix)] + public void Validation_Works(NewSubscriptionMatrixPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionMatrixPriceModelType.Matrix)] + public void SerializationRoundtrip_Works(NewSubscriptionMatrixPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMatrixPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewSubscriptionMatrixPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewSubscriptionMatrixPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewSubscriptionMatrixPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewSubscriptionMatrixPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceTest.cs new file mode 100644 index 00000000..c483cb2d --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceTest.cs @@ -0,0 +1,744 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionMatrixWithAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewSubscriptionMatrixWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixWithAllocationConfig, model.MatrixWithAllocationConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewSubscriptionMatrixWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + MatrixWithAllocationConfig expectedMatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }; + ApiEnum expectedModelType = + NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixWithAllocationConfig, deserialized.MatrixWithAllocationConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewSubscriptionMatrixWithAllocationPrice + { + Cadence = NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = [new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }], + }, + ModelType = NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionMatrixWithAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Annual)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Monthly)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Quarterly)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.OneTime)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Custom)] + public void Validation_Works(NewSubscriptionMatrixWithAllocationPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Annual)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Monthly)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Quarterly)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.OneTime)] + [InlineData(NewSubscriptionMatrixWithAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + NewSubscriptionMatrixWithAllocationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMatrixWithAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation)] + public void Validation_Works(NewSubscriptionMatrixWithAllocationPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation)] + public void SerializationRoundtrip_Works( + NewSubscriptionMatrixWithAllocationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMatrixWithAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceTest.cs new file mode 100644 index 00000000..064bb0c4 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceTest.cs @@ -0,0 +1,1040 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionMatrixWithDisplayNamePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual; + string expectedItemID = "item_id"; + Subscriptions::MatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + ApiEnum< + string, + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMatrixWithDisplayNameConfig, model.MatrixWithDisplayNameConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual; + string expectedItemID = "item_id"; + Subscriptions::MatrixWithDisplayNameConfig expectedMatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + ApiEnum< + string, + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMatrixWithDisplayNameConfig, deserialized.MatrixWithDisplayNameConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionMatrixWithDisplayNamePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MatrixWithDisplayNameConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, model.Dimension); + Assert.Equal(expectedUnitAmounts.Count, model.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], model.UnitAmounts[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedDimension = "dimension"; + List expectedUnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ]; + + Assert.Equal(expectedDimension, deserialized.Dimension); + Assert.Equal(expectedUnitAmounts.Count, deserialized.UnitAmounts.Count); + for (int i = 0; i < expectedUnitAmounts.Count; i++) + { + Assert.Equal(expectedUnitAmounts[i], deserialized.UnitAmounts[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfig + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } +} + +public class MatrixWithDisplayNameConfigUnitAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, model.DimensionValue); + Assert.Equal(expectedDisplayName, model.DisplayName); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedDimensionValue = "dimension_value"; + string expectedDisplayName = "display_name"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedDimensionValue, deserialized.DimensionValue); + Assert.Equal(expectedDisplayName, deserialized.DisplayName); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::MatrixWithDisplayNameConfigUnitAmount + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionMatrixWithDisplayNamePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName + )] + public void Validation_Works( + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceTest.cs new file mode 100644 index 00000000..e8b85f11 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceTest.cs @@ -0,0 +1,984 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionMaxGroupTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + Subscriptions::MaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + ApiEnum< + string, + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMaxGroupTieredPackageConfig, model.MaxGroupTieredPackageConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + Subscriptions::MaxGroupTieredPackageConfig expectedMaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + ApiEnum< + string, + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMaxGroupTieredPackageConfig, deserialized.MaxGroupTieredPackageConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionMaxGroupTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MaxGroupTieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfig + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } +} + +public class MaxGroupTieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::MaxGroupTieredPackageConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionMaxGroupTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage + )] + public void Validation_Works( + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMinimumCompositePriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMinimumCompositePriceTest.cs new file mode 100644 index 00000000..45fa1c25 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionMinimumCompositePriceTest.cs @@ -0,0 +1,820 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionMinimumCompositePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionMinimumCompositePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual; + string expectedItemID = "item_id"; + Subscriptions::MinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + ApiEnum< + string, + Subscriptions::NewSubscriptionMinimumCompositePriceModelType + > expectedModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionMinimumCompositePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedMinimumConfig, model.MinimumConfig); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionMinimumCompositePriceCadence + > expectedCadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual; + string expectedItemID = "item_id"; + Subscriptions::MinimumConfig expectedMinimumConfig = new() + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + ApiEnum< + string, + Subscriptions::NewSubscriptionMinimumCompositePriceModelType + > expectedModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum; + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionMinimumCompositePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedMinimumConfig, deserialized.MinimumConfig); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionMinimumCompositePrice + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionMinimumCompositePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionMinimumCompositePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionMinimumCompositePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class MinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::MinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedProrated, model.Prorated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::MinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::MinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedProrated, deserialized.Prorated); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::MinimumConfig + { + MinimumAmount = "minimum_amount", + Prorated = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::MinimumConfig { MinimumAmount = "minimum_amount" }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::MinimumConfig { MinimumAmount = "minimum_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Subscriptions::MinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::MinimumConfig + { + MinimumAmount = "minimum_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionMinimumCompositePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum)] + public void Validation_Works( + Subscriptions::NewSubscriptionMinimumCompositePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionMinimumCompositePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionMinimumCompositePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionMinimumCompositePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionMinimumCompositePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionMinimumCompositePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionMinimumCompositePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionPackagePriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionPackagePriceTest.cs new file mode 100644 index 00000000..09de87b0 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionPackagePriceTest.cs @@ -0,0 +1,676 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewSubscriptionPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewSubscriptionPackagePriceModelType.Package; + string expectedName = "Annual fee"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageConfig, model.PackageConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewSubscriptionPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewSubscriptionPackagePriceModelType.Package; + string expectedName = "Annual fee"; + PackageConfig expectedPackageConfig = new() + { + PackageAmount = "package_amount", + PackageSize = 1, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageConfig, deserialized.PackageConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewSubscriptionPackagePrice + { + Cadence = NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionPackagePriceCadence.Annual)] + [InlineData(NewSubscriptionPackagePriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionPackagePriceCadence.Monthly)] + [InlineData(NewSubscriptionPackagePriceCadence.Quarterly)] + [InlineData(NewSubscriptionPackagePriceCadence.OneTime)] + [InlineData(NewSubscriptionPackagePriceCadence.Custom)] + public void Validation_Works(NewSubscriptionPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionPackagePriceCadence.Annual)] + [InlineData(NewSubscriptionPackagePriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionPackagePriceCadence.Monthly)] + [InlineData(NewSubscriptionPackagePriceCadence.Quarterly)] + [InlineData(NewSubscriptionPackagePriceCadence.OneTime)] + [InlineData(NewSubscriptionPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewSubscriptionPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionPackagePriceModelType.Package)] + public void Validation_Works(NewSubscriptionPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionPackagePriceModelType.Package)] + public void SerializationRoundtrip_Works(NewSubscriptionPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewSubscriptionPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewSubscriptionPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewSubscriptionPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewSubscriptionPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceTest.cs new file mode 100644 index 00000000..eb66db28 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceTest.cs @@ -0,0 +1,844 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionPackageWithAllocationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation; + string expectedName = "Annual fee"; + Subscriptions::PackageWithAllocationConfig expectedPackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionPackageWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPackageWithAllocationConfig, model.PackageWithAllocationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation; + string expectedName = "Annual fee"; + Subscriptions::PackageWithAllocationConfig expectedPackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionPackageWithAllocationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPackageWithAllocationConfig, deserialized.PackageWithAllocationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionPackageWithAllocationPrice + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionPackageWithAllocationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionPackageWithAllocationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation + )] + public void Validation_Works( + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PackageWithAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, model.Allocation); + Assert.Equal(expectedPackageAmount, model.PackageAmount); + Assert.Equal(expectedPackageSize, model.PackageSize); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedAllocation = "allocation"; + string expectedPackageAmount = "package_amount"; + string expectedPackageSize = "package_size"; + + Assert.Equal(expectedAllocation, deserialized.Allocation); + Assert.Equal(expectedPackageAmount, deserialized.PackageAmount); + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PackageWithAllocationConfig + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }; + + model.Validate(); + } +} + +public class NewSubscriptionPackageWithAllocationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionPackageWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionPackageWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionPackageWithAllocationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionPackageWithAllocationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceTest.cs new file mode 100644 index 00000000..e335a45e --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceTest.cs @@ -0,0 +1,1438 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionScalableMatrixWithTieredPricingPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing; + string expectedName = "Annual fee"; + Subscriptions::ScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + model.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing; + string expectedName = "Annual fee"; + Subscriptions::ScalableMatrixWithTieredPricingConfig expectedScalableMatrixWithTieredPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedScalableMatrixWithTieredPricingConfig, + deserialized.ScalableMatrixWithTieredPricingConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionScalableMatrixWithTieredPricingPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual)] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.SemiAnnual + )] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Monthly)] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Quarterly + )] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual)] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.SemiAnnual + )] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Monthly)] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Quarterly + )] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionScalableMatrixWithTieredPricingPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing + )] + public void Validation_Works( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithTieredPricingConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class MatrixScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::MatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithTieredPricingConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ScalableMatrixWithTieredPricingConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceTest.cs new file mode 100644 index 00000000..5388d9d5 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceTest.cs @@ -0,0 +1,1286 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionScalableMatrixWithUnitPricingPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing; + string expectedName = "Annual fee"; + Subscriptions::ScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + model.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing; + string expectedName = "Annual fee"; + Subscriptions::ScalableMatrixWithUnitPricingConfig expectedScalableMatrixWithUnitPricingConfig = + new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedScalableMatrixWithUnitPricingConfig, + deserialized.ScalableMatrixWithUnitPricingConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionScalableMatrixWithUnitPricingPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionScalableMatrixWithUnitPricingPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing + )] + public void Validation_Works( + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ScalableMatrixWithUnitPricingConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, model.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, model.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], model.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, model.UnitPrice); + Assert.Equal(expectedProrate, model.Prorate); + Assert.Equal(expectedSecondDimension, model.SecondDimension); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedFirstDimension = "first_dimension"; + List expectedMatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ]; + string expectedUnitPrice = "unit_price"; + bool expectedProrate = true; + string expectedSecondDimension = "second_dimension"; + + Assert.Equal(expectedFirstDimension, deserialized.FirstDimension); + Assert.Equal(expectedMatrixScalingFactors.Count, deserialized.MatrixScalingFactors.Count); + for (int i = 0; i < expectedMatrixScalingFactors.Count; i++) + { + Assert.Equal(expectedMatrixScalingFactors[i], deserialized.MatrixScalingFactors[i]); + } + Assert.Equal(expectedUnitPrice, deserialized.UnitPrice); + Assert.Equal(expectedProrate, deserialized.Prorate); + Assert.Equal(expectedSecondDimension, deserialized.SecondDimension); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.False(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + Assert.Null(model.SecondDimension); + Assert.True(model.RawData.ContainsKey("second_dimension")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfig + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + + Prorate = null, + SecondDimension = null, + }; + + model.Validate(); + } +} + +public class ScalableMatrixWithUnitPricingConfigMatrixScalingFactorTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, model.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, model.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, model.SecondDimensionValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedFirstDimensionValue = "first_dimension_value"; + string expectedScalingFactor = "scaling_factor"; + string expectedSecondDimensionValue = "second_dimension_value"; + + Assert.Equal(expectedFirstDimensionValue, deserialized.FirstDimensionValue); + Assert.Equal(expectedScalingFactor, deserialized.ScalingFactor); + Assert.Equal(expectedSecondDimensionValue, deserialized.SecondDimensionValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + Assert.Null(model.SecondDimensionValue); + Assert.False(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + Assert.Null(model.SecondDimensionValue); + Assert.True(model.RawData.ContainsKey("second_dimension_value")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ScalableMatrixWithUnitPricingConfigMatrixScalingFactor + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + + SecondDimensionValue = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceTest.cs new file mode 100644 index 00000000..1278d67d --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceTest.cs @@ -0,0 +1,1030 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionThresholdTotalAmountPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount; + string expectedName = "Annual fee"; + Subscriptions::ThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionThresholdTotalAmountPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedThresholdTotalAmountConfig, model.ThresholdTotalAmountConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount; + string expectedName = "Annual fee"; + Subscriptions::ThresholdTotalAmountConfig expectedThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionThresholdTotalAmountPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedThresholdTotalAmountConfig, deserialized.ThresholdTotalAmountConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionThresholdTotalAmountPrice + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionThresholdTotalAmountPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionThresholdTotalAmountPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount + )] + public void Validation_Works( + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ThresholdTotalAmountConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, model.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], model.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ]; + bool expectedProrate = true; + + Assert.Equal(expectedConsumptionTable.Count, deserialized.ConsumptionTable.Count); + for (int i = 0; i < expectedConsumptionTable.Count; i++) + { + Assert.Equal(expectedConsumptionTable[i], deserialized.ConsumptionTable[i]); + } + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + Assert.Null(model.Prorate); + Assert.True(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ThresholdTotalAmountConfig + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + + Prorate = null, + }; + + model.Validate(); + } +} + +public class ConsumptionTableTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, model.Threshold); + Assert.Equal(expectedTotalAmount, model.TotalAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedThreshold = "threshold"; + string expectedTotalAmount = "total_amount"; + + Assert.Equal(expectedThreshold, deserialized.Threshold); + Assert.Equal(expectedTotalAmount, deserialized.TotalAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ConsumptionTable + { + Threshold = "threshold", + TotalAmount = "total_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionThresholdTotalAmountPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionThresholdTotalAmountPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPackagePriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPackagePriceTest.cs new file mode 100644 index 00000000..cc28b790 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPackagePriceTest.cs @@ -0,0 +1,934 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionTieredPackagePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackagePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage; + string expectedName = "Annual fee"; + Subscriptions::TieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredPackageConfig, model.TieredPackageConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackagePriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage; + string expectedName = "Annual fee"; + Subscriptions::TieredPackageConfig expectedTieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionTieredPackagePriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredPackageConfig, deserialized.TieredPackageConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackagePrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredPackagePriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Custom)] + public void Validation_Works(Subscriptions::NewSubscriptionTieredPackagePriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionTieredPackagePriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionTieredPackagePriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage)] + public void Validation_Works(Subscriptions::NewSubscriptionTieredPackagePriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionTieredPackagePriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPackageSize = "package_size"; + List expectedTiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredPackageConfig + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class TieredPackageConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredPackageConfigTier + { + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredPackagePriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionTieredPackagePriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionTieredPackagePriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceTest.cs new file mode 100644 index 00000000..f4c8ae8c --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceTest.cs @@ -0,0 +1,1141 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionTieredPackageWithMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum; + string expectedName = "Annual fee"; + Subscriptions::TieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredPackageWithMinimumConfig, model.TieredPackageWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence + > expectedCadence = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum; + string expectedName = "Annual fee"; + Subscriptions::TieredPackageWithMinimumConfig expectedTieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal( + expectedTieredPackageWithMinimumConfig, + deserialized.TieredPackageWithMinimumConfig + ); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredPackageWithMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionTieredPackageWithMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum + )] + public void Validation_Works( + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum + )] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredPackageWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, model.PackageSize); + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPackageSize = 0; + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ]; + + Assert.Equal(expectedPackageSize, deserialized.PackageSize); + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfig + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }; + + model.Validate(); + } +} + +public class TieredPackageWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPerUnit, model.PerUnit); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedPerUnit = "per_unit"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPerUnit, deserialized.PerUnit); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredPackageWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPriceTest.cs new file mode 100644 index 00000000..1f5423b2 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredPriceTest.cs @@ -0,0 +1,788 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionTieredPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewSubscriptionTieredPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewSubscriptionTieredPriceModelType.Tiered; + string expectedName = "Annual fee"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredConfig, model.TieredConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewSubscriptionTieredPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewSubscriptionTieredPriceModelType.Tiered; + string expectedName = "Annual fee"; + TieredConfig expectedTieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionTieredPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredConfig, deserialized.TieredConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewSubscriptionTieredPrice + { + Cadence = NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionTieredPriceCadence.Annual)] + [InlineData(NewSubscriptionTieredPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionTieredPriceCadence.Monthly)] + [InlineData(NewSubscriptionTieredPriceCadence.Quarterly)] + [InlineData(NewSubscriptionTieredPriceCadence.OneTime)] + [InlineData(NewSubscriptionTieredPriceCadence.Custom)] + public void Validation_Works(NewSubscriptionTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionTieredPriceCadence.Annual)] + [InlineData(NewSubscriptionTieredPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionTieredPriceCadence.Monthly)] + [InlineData(NewSubscriptionTieredPriceCadence.Quarterly)] + [InlineData(NewSubscriptionTieredPriceCadence.OneTime)] + [InlineData(NewSubscriptionTieredPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewSubscriptionTieredPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionTieredPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionTieredPriceModelType.Tiered)] + public void Validation_Works(NewSubscriptionTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionTieredPriceModelType.Tiered)] + public void SerializationRoundtrip_Works(NewSubscriptionTieredPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionTieredPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewSubscriptionTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewSubscriptionTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewSubscriptionTieredPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewSubscriptionTieredPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceTest.cs new file mode 100644 index 00000000..81674479 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceTest.cs @@ -0,0 +1,1260 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionTieredWithMinimumPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum; + string expectedName = "Annual fee"; + Subscriptions::TieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionTieredWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithMinimumConfig, model.TieredWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum; + string expectedName = "Annual fee"; + Subscriptions::TieredWithMinimumConfig expectedTieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionTieredWithMinimumPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithMinimumConfig, deserialized.TieredWithMinimumConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionTieredWithMinimumPrice + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredWithMinimumPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionTieredWithMinimumPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum)] + public void Validation_Works( + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithMinimumConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, model.HideZeroAmountTiers); + Assert.Equal(expectedProrate, model.Prorate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ]; + bool expectedHideZeroAmountTiers = true; + bool expectedProrate = true; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedHideZeroAmountTiers, deserialized.HideZeroAmountTiers); + Assert.Equal(expectedProrate, deserialized.Prorate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + Assert.Null(model.HideZeroAmountTiers); + Assert.False(model.RawData.ContainsKey("hide_zero_amount_tiers")); + Assert.Null(model.Prorate); + Assert.False(model.RawData.ContainsKey("prorate")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::TieredWithMinimumConfig + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + + // Null should be interpreted as omitted for these properties + HideZeroAmountTiers = null, + Prorate = null, + }; + + model.Validate(); + } +} + +public class TieredWithMinimumConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedMinimumAmount = "minimum_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredWithMinimumConfigTier + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionTieredWithMinimumPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionTieredWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionTieredWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionTieredWithMinimumPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionTieredWithMinimumPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitPriceTest.cs new file mode 100644 index 00000000..a6eb092a --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitPriceTest.cs @@ -0,0 +1,666 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionUnitPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + NewSubscriptionUnitPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewSubscriptionUnitPriceModelType.Unit; + string expectedName = "Annual fee"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionUnitPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitConfig, model.UnitConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + NewSubscriptionUnitPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum expectedModelType = + NewSubscriptionUnitPriceModelType.Unit; + string expectedName = "Annual fee"; + UnitConfig expectedUnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + NewSubscriptionUnitPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitConfig, deserialized.UnitConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new NewSubscriptionUnitPrice + { + Cadence = NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionUnitPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionUnitPriceCadence.Annual)] + [InlineData(NewSubscriptionUnitPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionUnitPriceCadence.Monthly)] + [InlineData(NewSubscriptionUnitPriceCadence.Quarterly)] + [InlineData(NewSubscriptionUnitPriceCadence.OneTime)] + [InlineData(NewSubscriptionUnitPriceCadence.Custom)] + public void Validation_Works(NewSubscriptionUnitPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionUnitPriceCadence.Annual)] + [InlineData(NewSubscriptionUnitPriceCadence.SemiAnnual)] + [InlineData(NewSubscriptionUnitPriceCadence.Monthly)] + [InlineData(NewSubscriptionUnitPriceCadence.Quarterly)] + [InlineData(NewSubscriptionUnitPriceCadence.OneTime)] + [InlineData(NewSubscriptionUnitPriceCadence.Custom)] + public void SerializationRoundtrip_Works(NewSubscriptionUnitPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionUnitPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(NewSubscriptionUnitPriceModelType.Unit)] + public void Validation_Works(NewSubscriptionUnitPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(NewSubscriptionUnitPriceModelType.Unit)] + public void SerializationRoundtrip_Works(NewSubscriptionUnitPriceModelType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionUnitPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + NewSubscriptionUnitPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + NewSubscriptionUnitPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + NewSubscriptionUnitPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + NewSubscriptionUnitPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceTest.cs new file mode 100644 index 00000000..4208ba5f --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceTest.cs @@ -0,0 +1,768 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionUnitWithPercentPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent; + string expectedName = "Annual fee"; + Subscriptions::UnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionUnitWithPercentPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitWithPercentConfig, model.UnitWithPercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent; + string expectedName = "Annual fee"; + Subscriptions::UnitWithPercentConfig expectedUnitWithPercentConfig = new() + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionUnitWithPercentPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitWithPercentConfig, deserialized.UnitWithPercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithPercentPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionUnitWithPercentPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Custom)] + public void Validation_Works(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionUnitWithPercentPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionUnitWithPercentPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent)] + public void Validation_Works( + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::UnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, model.Percent); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::UnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::UnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPercent = "percent"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedPercent, deserialized.Percent); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::UnitWithPercentConfig + { + Percent = "percent", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class NewSubscriptionUnitWithPercentPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionUnitWithPercentPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionUnitWithPercentPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionUnitWithPercentPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionUnitWithPercentPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceTest.cs b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceTest.cs new file mode 100644 index 00000000..a130b9e1 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceTest.cs @@ -0,0 +1,758 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class NewSubscriptionUnitWithProrationPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::NewSubscriptionUnitWithProrationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration; + string expectedName = "Annual fee"; + Subscriptions::UnitWithProrationConfig expectedUnitWithProrationConfig = new("unit_amount"); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionUnitWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.Equal(expectedModelType, model.ModelType); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedUnitWithProrationConfig, model.UnitWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::NewSubscriptionUnitWithProrationPriceCadence + > expectedCadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual; + string expectedItemID = "item_id"; + ApiEnum< + string, + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType + > expectedModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration; + string expectedName = "Annual fee"; + Subscriptions::UnitWithProrationConfig expectedUnitWithProrationConfig = new("unit_amount"); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::NewSubscriptionUnitWithProrationPriceConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.Equal(expectedModelType, deserialized.ModelType); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedUnitWithProrationConfig, deserialized.UnitWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::NewSubscriptionUnitWithProrationPrice + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class NewSubscriptionUnitWithProrationPriceCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Custom)] + public void Validation_Works( + Subscriptions::NewSubscriptionUnitWithProrationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.SemiAnnual)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Monthly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Quarterly)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.OneTime)] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionUnitWithProrationPriceCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class NewSubscriptionUnitWithProrationPriceModelTypeTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration)] + public void Validation_Works( + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration)] + public void SerializationRoundtrip_Works( + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UnitWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::UnitWithProrationConfig { UnitAmount = "unit_amount" }; + + model.Validate(); + } +} + +public class NewSubscriptionUnitWithProrationPriceConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::NewSubscriptionUnitWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::NewSubscriptionUnitWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionUnitWithProrationPriceConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::NewSubscriptionUnitWithProrationPriceConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionCancelParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionCancelParamsTest.cs new file mode 100644 index 00000000..76f70cfa --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionCancelParamsTest.cs @@ -0,0 +1,125 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionCancelParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionCancelParams + { + SubscriptionID = "subscription_id", + CancelOption = CancelOption.EndOfSubscriptionTerm, + AllowInvoiceCreditOrVoid = true, + CancellationDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedSubscriptionID = "subscription_id"; + ApiEnum expectedCancelOption = CancelOption.EndOfSubscriptionTerm; + bool expectedAllowInvoiceCreditOrVoid = true; + DateTimeOffset expectedCancellationDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedCancelOption, parameters.CancelOption); + Assert.Equal(expectedAllowInvoiceCreditOrVoid, parameters.AllowInvoiceCreditOrVoid); + Assert.Equal(expectedCancellationDate, parameters.CancellationDate); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionCancelParams + { + SubscriptionID = "subscription_id", + CancelOption = CancelOption.EndOfSubscriptionTerm, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.CancellationDate); + Assert.False(parameters.RawBodyData.ContainsKey("cancellation_date")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionCancelParams + { + SubscriptionID = "subscription_id", + CancelOption = CancelOption.EndOfSubscriptionTerm, + + AllowInvoiceCreditOrVoid = null, + CancellationDate = null, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.CancellationDate); + Assert.False(parameters.RawBodyData.ContainsKey("cancellation_date")); + } +} + +public class CancelOptionTest : TestBase +{ + [Theory] + [InlineData(CancelOption.EndOfSubscriptionTerm)] + [InlineData(CancelOption.Immediate)] + [InlineData(CancelOption.RequestedDate)] + public void Validation_Works(CancelOption rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(CancelOption.EndOfSubscriptionTerm)] + [InlineData(CancelOption.Immediate)] + [InlineData(CancelOption.RequestedDate)] + public void SerializationRoundtrip_Works(CancelOption rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionCreateParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionCreateParamsTest.cs new file mode 100644 index 00000000..2671957a --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionCreateParamsTest.cs @@ -0,0 +1,20302 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionCreateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new Subscriptions::SubscriptionCreateParams + { + AddAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AlignBillingWithSubscriptionStartDate = true, + AutoCollection = true, + AwsRegion = "aws_region", + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + CouponRedemptionCode = "coupon_redemption_code", + CreditsOverageRate = 0, + Currency = "currency", + CustomerID = "customer_id", + DefaultInvoiceMemo = "default_invoice_memo", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalCustomerID = "external_customer_id", + ExternalMarketplace = Subscriptions::ExternalMarketplace.Google, + ExternalMarketplaceReportingID = "external_marketplace_reporting_id", + ExternalPlanID = "ZMwNQefe7J3ecf7W", + Filter = "my_property > 100 AND my_other_property = 'bar'", + InitialPhaseOrder = 2, + InvoicingThreshold = "10.00", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + NetTerms = 0, + PerCreditOverageAmount = 0, + PlanID = "ZMwNQefe7J3ecf7W", + PlanVersionNumber = 0, + PriceOverrides = [JsonSerializer.Deserialize("{}")], + RemoveAdjustments = [new("h74gfhdjvn7ujokd")], + RemovePrices = + [ + new() { ExternalPriceID = "external_price_id", PriceID = "h74gfhdjvn7ujokd" }, + ], + ReplaceAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }, + ], + ReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TrialDurationDays = 0, + UsageCustomerIDs = ["string"], + }; + + List expectedAddAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + List expectedAddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAlignBillingWithSubscriptionStartDate = true; + bool expectedAutoCollection = true; + string expectedAwsRegion = "aws_region"; + BillingCycleAnchorConfiguration expectedBillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }; + string expectedCouponRedemptionCode = "coupon_redemption_code"; + double expectedCreditsOverageRate = 0; + string expectedCurrency = "currency"; + string expectedCustomerID = "customer_id"; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalCustomerID = "external_customer_id"; + ApiEnum expectedExternalMarketplace = + Subscriptions::ExternalMarketplace.Google; + string expectedExternalMarketplaceReportingID = "external_marketplace_reporting_id"; + string expectedExternalPlanID = "ZMwNQefe7J3ecf7W"; + string expectedFilter = "my_property > 100 AND my_other_property = 'bar'"; + long expectedInitialPhaseOrder = 2; + string expectedInvoicingThreshold = "10.00"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedName = "name"; + long expectedNetTerms = 0; + double expectedPerCreditOverageAmount = 0; + string expectedPlanID = "ZMwNQefe7J3ecf7W"; + long expectedPlanVersionNumber = 0; + List expectedPriceOverrides = [JsonSerializer.Deserialize("{}")]; + List expectedRemoveAdjustments = [new("h74gfhdjvn7ujokd")]; + List expectedRemovePrices = + [ + new() { ExternalPriceID = "external_price_id", PriceID = "h74gfhdjvn7ujokd" }, + ]; + List expectedReplaceAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }, + ]; + List expectedReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }, + ]; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedTrialDurationDays = 0; + List expectedUsageCustomerIDs = ["string"]; + + Assert.NotNull(parameters.AddAdjustments); + Assert.Equal(expectedAddAdjustments.Count, parameters.AddAdjustments.Count); + for (int i = 0; i < expectedAddAdjustments.Count; i++) + { + Assert.Equal(expectedAddAdjustments[i], parameters.AddAdjustments[i]); + } + Assert.NotNull(parameters.AddPrices); + Assert.Equal(expectedAddPrices.Count, parameters.AddPrices.Count); + for (int i = 0; i < expectedAddPrices.Count; i++) + { + Assert.Equal(expectedAddPrices[i], parameters.AddPrices[i]); + } + Assert.Equal( + expectedAlignBillingWithSubscriptionStartDate, + parameters.AlignBillingWithSubscriptionStartDate + ); + Assert.Equal(expectedAutoCollection, parameters.AutoCollection); + Assert.Equal(expectedAwsRegion, parameters.AwsRegion); + Assert.Equal( + expectedBillingCycleAnchorConfiguration, + parameters.BillingCycleAnchorConfiguration + ); + Assert.Equal(expectedCouponRedemptionCode, parameters.CouponRedemptionCode); + Assert.Equal(expectedCreditsOverageRate, parameters.CreditsOverageRate); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedCustomerID, parameters.CustomerID); + Assert.Equal(expectedDefaultInvoiceMemo, parameters.DefaultInvoiceMemo); + Assert.Equal(expectedEndDate, parameters.EndDate); + Assert.Equal(expectedExternalCustomerID, parameters.ExternalCustomerID); + Assert.Equal(expectedExternalMarketplace, parameters.ExternalMarketplace); + Assert.Equal( + expectedExternalMarketplaceReportingID, + parameters.ExternalMarketplaceReportingID + ); + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.Equal(expectedFilter, parameters.Filter); + Assert.Equal(expectedInitialPhaseOrder, parameters.InitialPhaseOrder); + Assert.Equal(expectedInvoicingThreshold, parameters.InvoicingThreshold); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedName, parameters.Name); + Assert.Equal(expectedNetTerms, parameters.NetTerms); + Assert.Equal(expectedPerCreditOverageAmount, parameters.PerCreditOverageAmount); + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedPlanVersionNumber, parameters.PlanVersionNumber); + Assert.NotNull(parameters.PriceOverrides); + Assert.Equal(expectedPriceOverrides.Count, parameters.PriceOverrides.Count); + for (int i = 0; i < expectedPriceOverrides.Count; i++) + { + Assert.True( + JsonElement.DeepEquals(expectedPriceOverrides[i], parameters.PriceOverrides[i]) + ); + } + Assert.NotNull(parameters.RemoveAdjustments); + Assert.Equal(expectedRemoveAdjustments.Count, parameters.RemoveAdjustments.Count); + for (int i = 0; i < expectedRemoveAdjustments.Count; i++) + { + Assert.Equal(expectedRemoveAdjustments[i], parameters.RemoveAdjustments[i]); + } + Assert.NotNull(parameters.RemovePrices); + Assert.Equal(expectedRemovePrices.Count, parameters.RemovePrices.Count); + for (int i = 0; i < expectedRemovePrices.Count; i++) + { + Assert.Equal(expectedRemovePrices[i], parameters.RemovePrices[i]); + } + Assert.NotNull(parameters.ReplaceAdjustments); + Assert.Equal(expectedReplaceAdjustments.Count, parameters.ReplaceAdjustments.Count); + for (int i = 0; i < expectedReplaceAdjustments.Count; i++) + { + Assert.Equal(expectedReplaceAdjustments[i], parameters.ReplaceAdjustments[i]); + } + Assert.NotNull(parameters.ReplacePrices); + Assert.Equal(expectedReplacePrices.Count, parameters.ReplacePrices.Count); + for (int i = 0; i < expectedReplacePrices.Count; i++) + { + Assert.Equal(expectedReplacePrices[i], parameters.ReplacePrices[i]); + } + Assert.Equal(expectedStartDate, parameters.StartDate); + Assert.Equal(expectedTrialDurationDays, parameters.TrialDurationDays); + Assert.NotNull(parameters.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, parameters.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], parameters.UsageCustomerIDs[i]); + } + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionCreateParams + { + AddAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + AwsRegion = "aws_region", + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + CouponRedemptionCode = "coupon_redemption_code", + CreditsOverageRate = 0, + Currency = "currency", + CustomerID = "customer_id", + DefaultInvoiceMemo = "default_invoice_memo", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalCustomerID = "external_customer_id", + ExternalMarketplace = Subscriptions::ExternalMarketplace.Google, + ExternalMarketplaceReportingID = "external_marketplace_reporting_id", + ExternalPlanID = "ZMwNQefe7J3ecf7W", + Filter = "my_property > 100 AND my_other_property = 'bar'", + InitialPhaseOrder = 2, + InvoicingThreshold = "10.00", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + NetTerms = 0, + PerCreditOverageAmount = 0, + PlanID = "ZMwNQefe7J3ecf7W", + PlanVersionNumber = 0, + PriceOverrides = [JsonSerializer.Deserialize("{}")], + RemoveAdjustments = [new("h74gfhdjvn7ujokd")], + RemovePrices = + [ + new() { ExternalPriceID = "external_price_id", PriceID = "h74gfhdjvn7ujokd" }, + ], + ReplaceAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }, + ], + ReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TrialDurationDays = 0, + UsageCustomerIDs = ["string"], + }; + + Assert.Null(parameters.AlignBillingWithSubscriptionStartDate); + Assert.False( + parameters.RawBodyData.ContainsKey("align_billing_with_subscription_start_date") + ); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionCreateParams + { + AddAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + AwsRegion = "aws_region", + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + CouponRedemptionCode = "coupon_redemption_code", + CreditsOverageRate = 0, + Currency = "currency", + CustomerID = "customer_id", + DefaultInvoiceMemo = "default_invoice_memo", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalCustomerID = "external_customer_id", + ExternalMarketplace = Subscriptions::ExternalMarketplace.Google, + ExternalMarketplaceReportingID = "external_marketplace_reporting_id", + ExternalPlanID = "ZMwNQefe7J3ecf7W", + Filter = "my_property > 100 AND my_other_property = 'bar'", + InitialPhaseOrder = 2, + InvoicingThreshold = "10.00", + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + NetTerms = 0, + PerCreditOverageAmount = 0, + PlanID = "ZMwNQefe7J3ecf7W", + PlanVersionNumber = 0, + PriceOverrides = [JsonSerializer.Deserialize("{}")], + RemoveAdjustments = [new("h74gfhdjvn7ujokd")], + RemovePrices = + [ + new() { ExternalPriceID = "external_price_id", PriceID = "h74gfhdjvn7ujokd" }, + ], + ReplaceAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }, + ], + ReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TrialDurationDays = 0, + UsageCustomerIDs = ["string"], + + // Null should be interpreted as omitted for these properties + AlignBillingWithSubscriptionStartDate = null, + }; + + Assert.Null(parameters.AlignBillingWithSubscriptionStartDate); + Assert.False( + parameters.RawBodyData.ContainsKey("align_billing_with_subscription_start_date") + ); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionCreateParams + { + AlignBillingWithSubscriptionStartDate = true, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AwsRegion); + Assert.False(parameters.RawBodyData.ContainsKey("aws_region")); + Assert.Null(parameters.BillingCycleAnchorConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("billing_cycle_anchor_configuration")); + Assert.Null(parameters.CouponRedemptionCode); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_redemption_code")); + Assert.Null(parameters.CreditsOverageRate); + Assert.False(parameters.RawBodyData.ContainsKey("credits_overage_rate")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.EndDate); + Assert.False(parameters.RawBodyData.ContainsKey("end_date")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.ExternalMarketplace); + Assert.False(parameters.RawBodyData.ContainsKey("external_marketplace")); + Assert.Null(parameters.ExternalMarketplaceReportingID); + Assert.False(parameters.RawBodyData.ContainsKey("external_marketplace_reporting_id")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Filter); + Assert.False(parameters.RawBodyData.ContainsKey("filter")); + Assert.Null(parameters.InitialPhaseOrder); + Assert.False(parameters.RawBodyData.ContainsKey("initial_phase_order")); + Assert.Null(parameters.InvoicingThreshold); + Assert.False(parameters.RawBodyData.ContainsKey("invoicing_threshold")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + Assert.Null(parameters.PerCreditOverageAmount); + Assert.False(parameters.RawBodyData.ContainsKey("per_credit_overage_amount")); + Assert.Null(parameters.PlanID); + Assert.False(parameters.RawBodyData.ContainsKey("plan_id")); + Assert.Null(parameters.PlanVersionNumber); + Assert.False(parameters.RawBodyData.ContainsKey("plan_version_number")); + Assert.Null(parameters.PriceOverrides); + Assert.False(parameters.RawBodyData.ContainsKey("price_overrides")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.StartDate); + Assert.False(parameters.RawBodyData.ContainsKey("start_date")); + Assert.Null(parameters.TrialDurationDays); + Assert.False(parameters.RawBodyData.ContainsKey("trial_duration_days")); + Assert.Null(parameters.UsageCustomerIDs); + Assert.False(parameters.RawBodyData.ContainsKey("usage_customer_ids")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new Subscriptions::SubscriptionCreateParams + { + AlignBillingWithSubscriptionStartDate = true, + + AddAdjustments = null, + AddPrices = null, + AutoCollection = null, + AwsRegion = null, + BillingCycleAnchorConfiguration = null, + CouponRedemptionCode = null, + CreditsOverageRate = null, + Currency = null, + CustomerID = null, + DefaultInvoiceMemo = null, + EndDate = null, + ExternalCustomerID = null, + ExternalMarketplace = null, + ExternalMarketplaceReportingID = null, + ExternalPlanID = null, + Filter = null, + InitialPhaseOrder = null, + InvoicingThreshold = null, + Metadata = null, + Name = null, + NetTerms = null, + PerCreditOverageAmount = null, + PlanID = null, + PlanVersionNumber = null, + PriceOverrides = null, + RemoveAdjustments = null, + RemovePrices = null, + ReplaceAdjustments = null, + ReplacePrices = null, + StartDate = null, + TrialDurationDays = null, + UsageCustomerIDs = null, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.AwsRegion); + Assert.False(parameters.RawBodyData.ContainsKey("aws_region")); + Assert.Null(parameters.BillingCycleAnchorConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("billing_cycle_anchor_configuration")); + Assert.Null(parameters.CouponRedemptionCode); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_redemption_code")); + Assert.Null(parameters.CreditsOverageRate); + Assert.False(parameters.RawBodyData.ContainsKey("credits_overage_rate")); + Assert.Null(parameters.Currency); + Assert.False(parameters.RawBodyData.ContainsKey("currency")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("customer_id")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.EndDate); + Assert.False(parameters.RawBodyData.ContainsKey("end_date")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawBodyData.ContainsKey("external_customer_id")); + Assert.Null(parameters.ExternalMarketplace); + Assert.False(parameters.RawBodyData.ContainsKey("external_marketplace")); + Assert.Null(parameters.ExternalMarketplaceReportingID); + Assert.False(parameters.RawBodyData.ContainsKey("external_marketplace_reporting_id")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Filter); + Assert.False(parameters.RawBodyData.ContainsKey("filter")); + Assert.Null(parameters.InitialPhaseOrder); + Assert.False(parameters.RawBodyData.ContainsKey("initial_phase_order")); + Assert.Null(parameters.InvoicingThreshold); + Assert.False(parameters.RawBodyData.ContainsKey("invoicing_threshold")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.Name); + Assert.False(parameters.RawBodyData.ContainsKey("name")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + Assert.Null(parameters.PerCreditOverageAmount); + Assert.False(parameters.RawBodyData.ContainsKey("per_credit_overage_amount")); + Assert.Null(parameters.PlanID); + Assert.False(parameters.RawBodyData.ContainsKey("plan_id")); + Assert.Null(parameters.PlanVersionNumber); + Assert.False(parameters.RawBodyData.ContainsKey("plan_version_number")); + Assert.Null(parameters.PriceOverrides); + Assert.False(parameters.RawBodyData.ContainsKey("price_overrides")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.StartDate); + Assert.False(parameters.RawBodyData.ContainsKey("start_date")); + Assert.Null(parameters.TrialDurationDays); + Assert.False(parameters.RawBodyData.ContainsKey("trial_duration_days")); + Assert.Null(parameters.UsageCustomerIDs); + Assert.False(parameters.RawBodyData.ContainsKey("usage_customer_ids")); + } +} + +public class AddAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Subscriptions::Adjustment expectedAdjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedPlanPhaseOrder = 0; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Subscriptions::Adjustment expectedAdjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedPlanPhaseOrder = 0; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + }; + + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + + EndDate = null, + PlanPhaseOrder = null, + StartDate = null, + }; + + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.StartDate); + Assert.True(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::AddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + + EndDate = null, + PlanPhaseOrder = null, + StartDate = null, + }; + + model.Validate(); + } +} + +public class AdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Subscriptions::Adjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Subscriptions::Adjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Subscriptions::Adjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Subscriptions::Adjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Subscriptions::Adjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Subscriptions::Adjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Subscriptions::Adjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Subscriptions::Adjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Subscriptions::Adjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Subscriptions::Adjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class AddPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalPriceID = "external_price_id"; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + long expectedPlanPhaseOrder = 0; + Subscriptions::Price expectedPrice = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalPriceID = "external_price_id"; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + long expectedPlanPhaseOrder = 0; + Subscriptions::Price expectedPrice = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::AddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::AddPrice { }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.MaximumAmount); + Assert.False(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.False(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::AddPrice { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::AddPrice + { + AllocationPrice = null, + Discounts = null, + EndDate = null, + ExternalPriceID = null, + MaximumAmount = null, + MinimumAmount = null, + PlanPhaseOrder = null, + Price = null, + PriceID = null, + StartDate = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.True(model.RawData.ContainsKey("discounts")); + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.MaximumAmount); + Assert.True(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.True(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + Assert.Null(model.StartDate); + Assert.True(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::AddPrice + { + AllocationPrice = null, + Discounts = null, + EndDate = null, + ExternalPriceID = null, + MaximumAmount = null, + MinimumAmount = null, + PlanPhaseOrder = null, + Price = null, + PriceID = null, + StartDate = null, + }; + + model.Validate(); + } +} + +public class PriceTest : TestBase +{ + [Fact] + public void NewSubscriptionUnitValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithPercentValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::TieredWithProration() + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithProrationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedAllocationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkWithProrationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::GroupedWithMinMaxThresholds() + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::CumulativeGroupedAllocation() + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMinimumCompositeValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::Percent() + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Subscriptions::Price value = new( + new Subscriptions::EventOutput() + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::BulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithPercentSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::TieredWithProration() + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithProrationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkWithProrationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::GroupedWithMinMaxThresholds() + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::CumulativeGroupedAllocation() + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMinimumCompositeSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::Percent() + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Subscriptions::Price value = new( + new Subscriptions::EventOutput() + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class BulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Subscriptions::BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Subscriptions::Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Subscriptions::BulkWithFiltersConfig expectedBulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = Subscriptions::Cadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::BulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::Cadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class BulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::BulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class FilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Filter { PropertyKey = "x", PropertyValue = "x" }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Filter { PropertyKey = "x", PropertyValue = "x" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Filter { PropertyKey = "x", PropertyValue = "x" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Filter { PropertyKey = "x", PropertyValue = "x" }; + + model.Validate(); + } +} + +public class TierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Tier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Tier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Tier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Tier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::Tier { UnitAmount = "unit_amount" }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::Tier { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::Tier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class CadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::Cadence.Annual)] + [InlineData(Subscriptions::Cadence.SemiAnnual)] + [InlineData(Subscriptions::Cadence.Monthly)] + [InlineData(Subscriptions::Cadence.Quarterly)] + [InlineData(Subscriptions::Cadence.OneTime)] + [InlineData(Subscriptions::Cadence.Custom)] + public void Validation_Works(Subscriptions::Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::Cadence.Annual)] + [InlineData(Subscriptions::Cadence.SemiAnnual)] + [InlineData(Subscriptions::Cadence.Monthly)] + [InlineData(Subscriptions::Cadence.Quarterly)] + [InlineData(Subscriptions::Cadence.OneTime)] + [InlineData(Subscriptions::Cadence.Custom)] + public void SerializationRoundtrip_Works(Subscriptions::Cadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class ConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::TieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::TieredWithProrationConfig expectedTieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::TieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::TieredWithProration + { + Cadence = Subscriptions::TieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class TieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::TieredWithProrationCadence.Annual)] + [InlineData(Subscriptions::TieredWithProrationCadence.SemiAnnual)] + [InlineData(Subscriptions::TieredWithProrationCadence.Monthly)] + [InlineData(Subscriptions::TieredWithProrationCadence.Quarterly)] + [InlineData(Subscriptions::TieredWithProrationCadence.OneTime)] + [InlineData(Subscriptions::TieredWithProrationCadence.Custom)] + public void Validation_Works(Subscriptions::TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::TieredWithProrationCadence.Annual)] + [InlineData(Subscriptions::TieredWithProrationCadence.SemiAnnual)] + [InlineData(Subscriptions::TieredWithProrationCadence.Monthly)] + [InlineData(Subscriptions::TieredWithProrationCadence.Quarterly)] + [InlineData(Subscriptions::TieredWithProrationCadence.OneTime)] + [InlineData(Subscriptions::TieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works(Subscriptions::TieredWithProrationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class TieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class TieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::TieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class TieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::TieredWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::TieredWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::TieredWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::TieredWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::GroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::GroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholds + { + Cadence = Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works(Subscriptions::GroupedWithMinMaxThresholdsCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(Subscriptions::GroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::GroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::GroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class GroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::GroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::CumulativeGroupedAllocationCadence.Annual; + Subscriptions::CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::CumulativeGroupedAllocationCadence.Annual; + Subscriptions::CumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::CumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocation + { + Cadence = Subscriptions::CumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Annual)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works(Subscriptions::CumulativeGroupedAllocationCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Annual)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Monthly)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.OneTime)] + [InlineData(Subscriptions::CumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::CumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class CumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::CumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class CumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::CumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::PercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::PercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::Percent + { + Cadence = Subscriptions::PercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class PercentCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::PercentCadence.Annual)] + [InlineData(Subscriptions::PercentCadence.SemiAnnual)] + [InlineData(Subscriptions::PercentCadence.Monthly)] + [InlineData(Subscriptions::PercentCadence.Quarterly)] + [InlineData(Subscriptions::PercentCadence.OneTime)] + [InlineData(Subscriptions::PercentCadence.Custom)] + public void Validation_Works(Subscriptions::PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::PercentCadence.Annual)] + [InlineData(Subscriptions::PercentCadence.SemiAnnual)] + [InlineData(Subscriptions::PercentCadence.Monthly)] + [InlineData(Subscriptions::PercentCadence.Quarterly)] + [InlineData(Subscriptions::PercentCadence.OneTime)] + [InlineData(Subscriptions::PercentCadence.Custom)] + public void SerializationRoundtrip_Works(Subscriptions::PercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::PercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::PercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::PercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::PercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::EventOutputCadence.Annual; + Subscriptions::EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::EventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::EventOutputCadence.Annual; + Subscriptions::EventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::EventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::EventOutput + { + Cadence = Subscriptions::EventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class EventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::EventOutputCadence.Annual)] + [InlineData(Subscriptions::EventOutputCadence.SemiAnnual)] + [InlineData(Subscriptions::EventOutputCadence.Monthly)] + [InlineData(Subscriptions::EventOutputCadence.Quarterly)] + [InlineData(Subscriptions::EventOutputCadence.OneTime)] + [InlineData(Subscriptions::EventOutputCadence.Custom)] + public void Validation_Works(Subscriptions::EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::EventOutputCadence.Annual)] + [InlineData(Subscriptions::EventOutputCadence.SemiAnnual)] + [InlineData(Subscriptions::EventOutputCadence.Monthly)] + [InlineData(Subscriptions::EventOutputCadence.Quarterly)] + [InlineData(Subscriptions::EventOutputCadence.OneTime)] + [InlineData(Subscriptions::EventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(Subscriptions::EventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class EventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::EventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::EventOutputConfig { UnitRatingKey = "x" }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::EventOutputConfig { UnitRatingKey = "x" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::EventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class EventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::EventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::EventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::EventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::EventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ExternalMarketplaceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ExternalMarketplace.Google)] + [InlineData(Subscriptions::ExternalMarketplace.Aws)] + [InlineData(Subscriptions::ExternalMarketplace.Azure)] + public void Validation_Works(Subscriptions::ExternalMarketplace rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ExternalMarketplace.Google)] + [InlineData(Subscriptions::ExternalMarketplace.Aws)] + [InlineData(Subscriptions::ExternalMarketplace.Azure)] + public void SerializationRoundtrip_Works(Subscriptions::ExternalMarketplace rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class RemoveAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::RemoveAdjustment { AdjustmentID = "h74gfhdjvn7ujokd" }; + + string expectedAdjustmentID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedAdjustmentID, model.AdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::RemoveAdjustment { AdjustmentID = "h74gfhdjvn7ujokd" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::RemoveAdjustment { AdjustmentID = "h74gfhdjvn7ujokd" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAdjustmentID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedAdjustmentID, deserialized.AdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::RemoveAdjustment { AdjustmentID = "h74gfhdjvn7ujokd" }; + + model.Validate(); + } +} + +public class RemovePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::RemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + string expectedExternalPriceID = "external_price_id"; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::RemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::RemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedExternalPriceID = "external_price_id"; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::RemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::RemovePrice { }; + + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::RemovePrice { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::RemovePrice { ExternalPriceID = null, PriceID = null }; + + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::RemovePrice { ExternalPriceID = null, PriceID = null }; + + model.Validate(); + } +} + +public class ReplaceAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + Subscriptions::ReplaceAdjustmentAdjustment expectedAdjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Subscriptions::ReplaceAdjustmentAdjustment expectedAdjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class ReplaceAdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Subscriptions::ReplaceAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + string expectedReplacesPriceID = "replaces_price_id"; + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 2; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + Subscriptions::ReplacePricePrice expectedPrice = + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedReplacesPriceID = "replaces_price_id"; + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 2; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + Subscriptions::ReplacePricePrice expectedPrice = + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePrice { ReplacesPriceID = "replaces_price_id" }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.MaximumAmount); + Assert.False(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.False(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePrice { ReplacesPriceID = "replaces_price_id" }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + Discounts = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + MaximumAmount = null, + MinimumAmount = null, + Price = null, + PriceID = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.True(model.RawData.ContainsKey("discounts")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.MaximumAmount); + Assert.True(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.True(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + Discounts = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + MaximumAmount = null, + MinimumAmount = null, + Price = null, + PriceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTest : TestBase +{ + [Fact] + public void NewSubscriptionUnitValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithPercentValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceTieredWithProration() + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithProrationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedAllocationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkWithProrationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMinimumCompositeValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePricePercent() + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceEventOutput() + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithPercentSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceTieredWithProration() + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithProrationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkWithProrationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMinimumCompositeSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePricePercent() + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePrice value = new( + new Subscriptions::ReplacePricePriceEventOutput() + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceBulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Custom)] + public void Validation_Works(Subscriptions::ReplacePricePriceBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceBulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::ReplacePricePriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceBulkWithFiltersConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceBulkWithFiltersConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceTieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::ReplacePricePriceTieredWithProrationCadence + > expectedCadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::ReplacePricePriceTieredWithProrationCadence + > expectedCadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProration + { + Cadence = Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Custom)] + public void Validation_Works( + Subscriptions::ReplacePricePriceTieredWithProrationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceTieredWithProrationCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::ReplacePricePriceTieredWithProrationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceTieredWithProrationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceTieredWithProrationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works( + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence + > expectedCadence = + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence + > expectedCadence = + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceCumulativeGroupedAllocation + { + Cadence = Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works( + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::ReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::ReplacePricePricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::ReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::ReplacePricePricePercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePricePercent + { + Cadence = Subscriptions::ReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Custom)] + public void Validation_Works(Subscriptions::ReplacePricePricePercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePricePercentCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::ReplacePricePricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePricePercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePricePercentPercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePricePercentPercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePricePercentPercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePricePercentPercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class ReplacePricePricePercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ReplacePricePricePercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ReplacePricePricePercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePricePercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePricePercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum expectedCadence = + Subscriptions::ReplacePricePriceEventOutputCadence.Annual; + Subscriptions::ReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::ReplacePricePriceEventOutputCadence.Annual; + Subscriptions::ReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::ReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutput + { + Cadence = Subscriptions::ReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Custom)] + public void Validation_Works(Subscriptions::ReplacePricePriceEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Annual)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.SemiAnnual)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Monthly)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Quarterly)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.OneTime)] + [InlineData(Subscriptions::ReplacePricePriceEventOutputCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::ReplacePricePriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ReplacePricePriceEventOutputEventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::ReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class ReplacePricePriceEventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::ReplacePricePriceEventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::ReplacePricePriceEventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceEventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::ReplacePricePriceEventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchCostsParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchCostsParamsTest.cs new file mode 100644 index 00000000..b121972c --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchCostsParamsTest.cs @@ -0,0 +1,131 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchCostsParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionFetchCostsParams + { + SubscriptionID = "subscription_id", + Currency = "currency", + TimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"), + TimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"), + ViewMode = ViewMode.Periodic, + }; + + string expectedSubscriptionID = "subscription_id"; + string expectedCurrency = "currency"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"); + ApiEnum expectedViewMode = ViewMode.Periodic; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedCurrency, parameters.Currency); + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedViewMode, parameters.ViewMode); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionFetchCostsParams { SubscriptionID = "subscription_id" }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionFetchCostsParams + { + SubscriptionID = "subscription_id", + + Currency = null, + TimeframeEnd = null, + TimeframeStart = null, + ViewMode = null, + }; + + Assert.Null(parameters.Currency); + Assert.False(parameters.RawQueryData.ContainsKey("currency")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } +} + +public class ViewModeTest : TestBase +{ + [Theory] + [InlineData(ViewMode.Periodic)] + [InlineData(ViewMode.Cumulative)] + public void Validation_Works(ViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ViewMode.Periodic)] + [InlineData(ViewMode.Cumulative)] + public void SerializationRoundtrip_Works(ViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchCostsResponseTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchCostsResponseTest.cs new file mode 100644 index 00000000..e275a182 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchCostsResponseTest.cs @@ -0,0 +1,871 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchCostsResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionFetchCostsResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + List expectedData = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionFetchCostsResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionFetchCostsResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionFetchCostsResponse + { + Data = + [ + new() + { + PerPriceCosts = + [ + new() + { + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + PriceID = "price_id", + Subtotal = "subtotal", + Total = "total", + Quantity = 0, + }, + ], + Subtotal = "subtotal", + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Total = "total", + }, + ], + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchParamsTest.cs new file mode 100644 index 00000000..adc2a6f7 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchParamsTest.cs @@ -0,0 +1,16 @@ +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionFetchParams { SubscriptionID = "subscription_id" }; + + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchSchedulePageResponseTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchSchedulePageResponseTest.cs new file mode 100644 index 00000000..932e019b --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchSchedulePageResponseTest.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchSchedulePageResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionFetchSchedulePageResponse + { + Data = + [ + new() + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionFetchSchedulePageResponse + { + Data = + [ + new() + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionFetchSchedulePageResponse + { + Data = + [ + new() + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionFetchSchedulePageResponse + { + Data = + [ + new() + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchScheduleParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchScheduleParamsTest.cs new file mode 100644 index 00000000..713b7af1 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchScheduleParamsTest.cs @@ -0,0 +1,123 @@ +using System; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchScheduleParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionFetchScheduleParams + { + SubscriptionID = "subscription_id", + Cursor = "cursor", + Limit = 1, + StartDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedSubscriptionID = "subscription_id"; + string expectedCursor = "cursor"; + long expectedLimit = 1; + DateTimeOffset expectedStartDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedStartDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedStartDateGt, parameters.StartDateGt); + Assert.Equal(expectedStartDateGte, parameters.StartDateGte); + Assert.Equal(expectedStartDateLt, parameters.StartDateLt); + Assert.Equal(expectedStartDateLte, parameters.StartDateLte); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionFetchScheduleParams + { + SubscriptionID = "subscription_id", + Cursor = "cursor", + StartDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new SubscriptionFetchScheduleParams + { + SubscriptionID = "subscription_id", + Cursor = "cursor", + StartDateGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDateLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionFetchScheduleParams + { + SubscriptionID = "subscription_id", + Limit = 1, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.StartDateGt); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[gt]")); + Assert.Null(parameters.StartDateGte); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[gte]")); + Assert.Null(parameters.StartDateLt); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[lt]")); + Assert.Null(parameters.StartDateLte); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[lte]")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionFetchScheduleParams + { + SubscriptionID = "subscription_id", + Limit = 1, + + Cursor = null, + StartDateGt = null, + StartDateGte = null, + StartDateLt = null, + StartDateLte = null, + }; + + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.StartDateGt); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[gt]")); + Assert.Null(parameters.StartDateGte); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[gte]")); + Assert.Null(parameters.StartDateLt); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[lt]")); + Assert.Null(parameters.StartDateLte); + Assert.False(parameters.RawQueryData.ContainsKey("start_date[lte]")); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchScheduleResponseTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchScheduleResponseTest.cs new file mode 100644 index 00000000..a7db1c1a --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchScheduleResponseTest.cs @@ -0,0 +1,191 @@ +using System; +using System.Text.Json; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchScheduleResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionFetchScheduleResponse + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Plan expectedPlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedPlan, model.Plan); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionFetchScheduleResponse + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionFetchScheduleResponse + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Plan expectedPlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedPlan, deserialized.Plan); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionFetchScheduleResponse + { + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Plan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class PlanTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + string expectedID = "m2t5akQeh2obwxeU"; + string expectedExternalPlanID = "m2t5akQeh2obwxeU"; + string expectedName = "Example plan"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedExternalPlanID, model.ExternalPlanID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "m2t5akQeh2obwxeU"; + string expectedExternalPlanID = "m2t5akQeh2obwxeU"; + string expectedName = "Example plan"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedExternalPlanID, deserialized.ExternalPlanID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new Plan + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchUsageParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchUsageParamsTest.cs new file mode 100644 index 00000000..edd8f545 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionFetchUsageParamsTest.cs @@ -0,0 +1,238 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionFetchUsageParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionFetchUsageParams + { + SubscriptionID = "subscription_id", + BillableMetricID = "billable_metric_id", + FirstDimensionKey = "first_dimension_key", + FirstDimensionValue = "first_dimension_value", + Granularity = Granularity.Day, + GroupBy = "group_by", + SecondDimensionKey = "second_dimension_key", + SecondDimensionValue = "second_dimension_value", + TimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"), + TimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"), + ViewMode = SubscriptionFetchUsageParamsViewMode.Periodic, + }; + + string expectedSubscriptionID = "subscription_id"; + string expectedBillableMetricID = "billable_metric_id"; + string expectedFirstDimensionKey = "first_dimension_key"; + string expectedFirstDimensionValue = "first_dimension_value"; + ApiEnum expectedGranularity = Granularity.Day; + string expectedGroupBy = "group_by"; + string expectedSecondDimensionKey = "second_dimension_key"; + string expectedSecondDimensionValue = "second_dimension_value"; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2022-03-01T05:00:00Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2022-02-01T05:00:00Z"); + ApiEnum expectedViewMode = + SubscriptionFetchUsageParamsViewMode.Periodic; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedBillableMetricID, parameters.BillableMetricID); + Assert.Equal(expectedFirstDimensionKey, parameters.FirstDimensionKey); + Assert.Equal(expectedFirstDimensionValue, parameters.FirstDimensionValue); + Assert.Equal(expectedGranularity, parameters.Granularity); + Assert.Equal(expectedGroupBy, parameters.GroupBy); + Assert.Equal(expectedSecondDimensionKey, parameters.SecondDimensionKey); + Assert.Equal(expectedSecondDimensionValue, parameters.SecondDimensionValue); + Assert.Equal(expectedTimeframeEnd, parameters.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, parameters.TimeframeStart); + Assert.Equal(expectedViewMode, parameters.ViewMode); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionFetchUsageParams { SubscriptionID = "subscription_id" }; + + Assert.Null(parameters.BillableMetricID); + Assert.False(parameters.RawQueryData.ContainsKey("billable_metric_id")); + Assert.Null(parameters.FirstDimensionKey); + Assert.False(parameters.RawQueryData.ContainsKey("first_dimension_key")); + Assert.Null(parameters.FirstDimensionValue); + Assert.False(parameters.RawQueryData.ContainsKey("first_dimension_value")); + Assert.Null(parameters.Granularity); + Assert.False(parameters.RawQueryData.ContainsKey("granularity")); + Assert.Null(parameters.GroupBy); + Assert.False(parameters.RawQueryData.ContainsKey("group_by")); + Assert.Null(parameters.SecondDimensionKey); + Assert.False(parameters.RawQueryData.ContainsKey("second_dimension_key")); + Assert.Null(parameters.SecondDimensionValue); + Assert.False(parameters.RawQueryData.ContainsKey("second_dimension_value")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionFetchUsageParams + { + SubscriptionID = "subscription_id", + + BillableMetricID = null, + FirstDimensionKey = null, + FirstDimensionValue = null, + Granularity = null, + GroupBy = null, + SecondDimensionKey = null, + SecondDimensionValue = null, + TimeframeEnd = null, + TimeframeStart = null, + ViewMode = null, + }; + + Assert.Null(parameters.BillableMetricID); + Assert.False(parameters.RawQueryData.ContainsKey("billable_metric_id")); + Assert.Null(parameters.FirstDimensionKey); + Assert.False(parameters.RawQueryData.ContainsKey("first_dimension_key")); + Assert.Null(parameters.FirstDimensionValue); + Assert.False(parameters.RawQueryData.ContainsKey("first_dimension_value")); + Assert.Null(parameters.Granularity); + Assert.False(parameters.RawQueryData.ContainsKey("granularity")); + Assert.Null(parameters.GroupBy); + Assert.False(parameters.RawQueryData.ContainsKey("group_by")); + Assert.Null(parameters.SecondDimensionKey); + Assert.False(parameters.RawQueryData.ContainsKey("second_dimension_key")); + Assert.Null(parameters.SecondDimensionValue); + Assert.False(parameters.RawQueryData.ContainsKey("second_dimension_value")); + Assert.Null(parameters.TimeframeEnd); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_end")); + Assert.Null(parameters.TimeframeStart); + Assert.False(parameters.RawQueryData.ContainsKey("timeframe_start")); + Assert.Null(parameters.ViewMode); + Assert.False(parameters.RawQueryData.ContainsKey("view_mode")); + } +} + +public class GranularityTest : TestBase +{ + [Theory] + [InlineData(Granularity.Day)] + public void Validation_Works(Granularity rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Granularity.Day)] + public void SerializationRoundtrip_Works(Granularity rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionFetchUsageParamsViewModeTest : TestBase +{ + [Theory] + [InlineData(SubscriptionFetchUsageParamsViewMode.Periodic)] + [InlineData(SubscriptionFetchUsageParamsViewMode.Cumulative)] + public void Validation_Works(SubscriptionFetchUsageParamsViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SubscriptionFetchUsageParamsViewMode.Periodic)] + [InlineData(SubscriptionFetchUsageParamsViewMode.Cumulative)] + public void SerializationRoundtrip_Works(SubscriptionFetchUsageParamsViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionListParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionListParamsTest.cs new file mode 100644 index 00000000..311919f6 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionListParamsTest.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionListParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + CustomerID = ["string"], + ExternalCustomerID = ["string"], + ExternalPlanID = "external_plan_id", + Limit = 1, + PlanID = "plan_id", + Status = Status.Active, + }; + + DateTimeOffset expectedCreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedCursor = "cursor"; + List expectedCustomerID = ["string"]; + List expectedExternalCustomerID = ["string"]; + string expectedExternalPlanID = "external_plan_id"; + long expectedLimit = 1; + string expectedPlanID = "plan_id"; + ApiEnum expectedStatus = Status.Active; + + Assert.Equal(expectedCreatedAtGt, parameters.CreatedAtGt); + Assert.Equal(expectedCreatedAtGte, parameters.CreatedAtGte); + Assert.Equal(expectedCreatedAtLt, parameters.CreatedAtLt); + Assert.Equal(expectedCreatedAtLte, parameters.CreatedAtLte); + Assert.Equal(expectedCursor, parameters.Cursor); + Assert.NotNull(parameters.CustomerID); + Assert.Equal(expectedCustomerID.Count, parameters.CustomerID.Count); + for (int i = 0; i < expectedCustomerID.Count; i++) + { + Assert.Equal(expectedCustomerID[i], parameters.CustomerID[i]); + } + Assert.NotNull(parameters.ExternalCustomerID); + Assert.Equal(expectedExternalCustomerID.Count, parameters.ExternalCustomerID.Count); + for (int i = 0; i < expectedExternalCustomerID.Count; i++) + { + Assert.Equal(expectedExternalCustomerID[i], parameters.ExternalCustomerID[i]); + } + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.Equal(expectedLimit, parameters.Limit); + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedStatus, parameters.Status); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + CustomerID = ["string"], + ExternalCustomerID = ["string"], + ExternalPlanID = "external_plan_id", + PlanID = "plan_id", + Status = Status.Active, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new SubscriptionListParams + { + CreatedAtGt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtGte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreatedAtLte = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Cursor = "cursor", + CustomerID = ["string"], + ExternalCustomerID = ["string"], + ExternalPlanID = "external_plan_id", + PlanID = "plan_id", + Status = Status.Active, + + // Null should be interpreted as omitted for these properties + Limit = null, + }; + + Assert.Null(parameters.Limit); + Assert.False(parameters.RawQueryData.ContainsKey("limit")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionListParams { Limit = 1 }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("external_customer_id")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawQueryData.ContainsKey("external_plan_id")); + Assert.Null(parameters.PlanID); + Assert.False(parameters.RawQueryData.ContainsKey("plan_id")); + Assert.Null(parameters.Status); + Assert.False(parameters.RawQueryData.ContainsKey("status")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionListParams + { + Limit = 1, + + CreatedAtGt = null, + CreatedAtGte = null, + CreatedAtLt = null, + CreatedAtLte = null, + Cursor = null, + CustomerID = null, + ExternalCustomerID = null, + ExternalPlanID = null, + PlanID = null, + Status = null, + }; + + Assert.Null(parameters.CreatedAtGt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gt]")); + Assert.Null(parameters.CreatedAtGte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[gte]")); + Assert.Null(parameters.CreatedAtLt); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lt]")); + Assert.Null(parameters.CreatedAtLte); + Assert.False(parameters.RawQueryData.ContainsKey("created_at[lte]")); + Assert.Null(parameters.Cursor); + Assert.False(parameters.RawQueryData.ContainsKey("cursor")); + Assert.Null(parameters.CustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("customer_id")); + Assert.Null(parameters.ExternalCustomerID); + Assert.False(parameters.RawQueryData.ContainsKey("external_customer_id")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawQueryData.ContainsKey("external_plan_id")); + Assert.Null(parameters.PlanID); + Assert.False(parameters.RawQueryData.ContainsKey("plan_id")); + Assert.Null(parameters.Status); + Assert.False(parameters.RawQueryData.ContainsKey("status")); + } +} + +public class StatusTest : TestBase +{ + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Ended)] + [InlineData(Status.Upcoming)] + public void Validation_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Status.Active)] + [InlineData(Status.Ended)] + [InlineData(Status.Upcoming)] + public void SerializationRoundtrip_Works(Status rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionPriceIntervalsParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionPriceIntervalsParamsTest.cs new file mode 100644 index 00000000..fe18a18e --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionPriceIntervalsParamsTest.cs @@ -0,0 +1,10520 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionPriceIntervalsParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new Subscriptions::SubscriptionPriceIntervalsParams + { + SubscriptionID = "subscription_id", + Add = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }, + ], + AddAdjustments = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AllowInvoiceCreditOrVoid = true, + CanDeferBilling = true, + Edit = + [ + new() + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + EditAdjustments = + [ + new() + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + }; + + string expectedSubscriptionID = "subscription_id"; + List expectedAdd = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }, + ]; + List expectedAddAdjustments = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAllowInvoiceCreditOrVoid = true; + bool expectedCanDeferBilling = true; + List expectedEdit = + [ + new() + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ]; + List expectedEditAdjustments = + [ + new() + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.NotNull(parameters.Add); + Assert.Equal(expectedAdd.Count, parameters.Add.Count); + for (int i = 0; i < expectedAdd.Count; i++) + { + Assert.Equal(expectedAdd[i], parameters.Add[i]); + } + Assert.NotNull(parameters.AddAdjustments); + Assert.Equal(expectedAddAdjustments.Count, parameters.AddAdjustments.Count); + for (int i = 0; i < expectedAddAdjustments.Count; i++) + { + Assert.Equal(expectedAddAdjustments[i], parameters.AddAdjustments[i]); + } + Assert.Equal(expectedAllowInvoiceCreditOrVoid, parameters.AllowInvoiceCreditOrVoid); + Assert.Equal(expectedCanDeferBilling, parameters.CanDeferBilling); + Assert.NotNull(parameters.Edit); + Assert.Equal(expectedEdit.Count, parameters.Edit.Count); + for (int i = 0; i < expectedEdit.Count; i++) + { + Assert.Equal(expectedEdit[i], parameters.Edit[i]); + } + Assert.NotNull(parameters.EditAdjustments); + Assert.Equal(expectedEditAdjustments.Count, parameters.EditAdjustments.Count); + for (int i = 0; i < expectedEditAdjustments.Count; i++) + { + Assert.Equal(expectedEditAdjustments[i], parameters.EditAdjustments[i]); + } + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionPriceIntervalsParams + { + SubscriptionID = "subscription_id", + AllowInvoiceCreditOrVoid = true, + CanDeferBilling = true, + }; + + Assert.Null(parameters.Add); + Assert.False(parameters.RawBodyData.ContainsKey("add")); + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.Edit); + Assert.False(parameters.RawBodyData.ContainsKey("edit")); + Assert.Null(parameters.EditAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("edit_adjustments")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionPriceIntervalsParams + { + SubscriptionID = "subscription_id", + AllowInvoiceCreditOrVoid = true, + CanDeferBilling = true, + + // Null should be interpreted as omitted for these properties + Add = null, + AddAdjustments = null, + Edit = null, + EditAdjustments = null, + }; + + Assert.Null(parameters.Add); + Assert.False(parameters.RawBodyData.ContainsKey("add")); + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.Edit); + Assert.False(parameters.RawBodyData.ContainsKey("edit")); + Assert.Null(parameters.EditAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("edit_adjustments")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionPriceIntervalsParams + { + SubscriptionID = "subscription_id", + Add = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }, + ], + AddAdjustments = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Edit = + [ + new() + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + EditAdjustments = + [ + new() + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.CanDeferBilling); + Assert.False(parameters.RawBodyData.ContainsKey("can_defer_billing")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new Subscriptions::SubscriptionPriceIntervalsParams + { + SubscriptionID = "subscription_id", + Add = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }, + ], + AddAdjustments = + [ + new() + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Edit = + [ + new() + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + EditAdjustments = + [ + new() + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + + AllowInvoiceCreditOrVoid = null, + CanDeferBilling = null, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.CanDeferBilling); + Assert.False(parameters.RawBodyData.ContainsKey("can_defer_billing")); + } +} + +public class AddTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }; + + Subscriptions::StartDate expectedStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + bool expectedCanDeferBilling = true; + List expectedDiscounts = [new Subscriptions::Amount(0)]; + Subscriptions::EndDate expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalPriceID = "external_price_id"; + string expectedFilter = "my_property > 100 AND my_other_property = 'bar'"; + List expectedFixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ]; + double expectedMaximumAmount = 0; + double expectedMinimumAmount = 0; + Subscriptions::PriceModel expectedPrice = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.Equal(expectedCanDeferBilling, model.CanDeferBilling); + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFilter, model.Filter); + Assert.NotNull(model.FixedFeeQuantityTransitions); + Assert.Equal( + expectedFixedFeeQuantityTransitions.Count, + model.FixedFeeQuantityTransitions.Count + ); + for (int i = 0; i < expectedFixedFeeQuantityTransitions.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantityTransitions[i], + model.FixedFeeQuantityTransitions[i] + ); + } + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + Subscriptions::StartDate expectedStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + bool expectedCanDeferBilling = true; + List expectedDiscounts = [new Subscriptions::Amount(0)]; + Subscriptions::EndDate expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalPriceID = "external_price_id"; + string expectedFilter = "my_property > 100 AND my_other_property = 'bar'"; + List expectedFixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ]; + double expectedMaximumAmount = 0; + double expectedMinimumAmount = 0; + Subscriptions::PriceModel expectedPrice = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.Equal(expectedCanDeferBilling, deserialized.CanDeferBilling); + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.NotNull(deserialized.FixedFeeQuantityTransitions); + Assert.Equal( + expectedFixedFeeQuantityTransitions.Count, + deserialized.FixedFeeQuantityTransitions.Count + ); + for (int i = 0; i < expectedFixedFeeQuantityTransitions.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantityTransitions[i], + deserialized.FixedFeeQuantityTransitions[i] + ); + } + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + CanDeferBilling = true, + Discounts = [new Subscriptions::Amount(0)], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + MaximumAmount = 0, + MinimumAmount = 0, + Price = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + PriceID = "h74gfhdjvn7ujokd", + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.CanDeferBilling); + Assert.False(model.RawData.ContainsKey("can_defer_billing")); + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.Filter); + Assert.False(model.RawData.ContainsKey("filter")); + Assert.Null(model.FixedFeeQuantityTransitions); + Assert.False(model.RawData.ContainsKey("fixed_fee_quantity_transitions")); + Assert.Null(model.MaximumAmount); + Assert.False(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.False(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + Assert.Null(model.UsageCustomerIDs); + Assert.False(model.RawData.ContainsKey("usage_customer_ids")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + AllocationPrice = null, + CanDeferBilling = null, + Discounts = null, + EndDate = null, + ExternalPriceID = null, + Filter = null, + FixedFeeQuantityTransitions = null, + MaximumAmount = null, + MinimumAmount = null, + Price = null, + PriceID = null, + UsageCustomerIDs = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.CanDeferBilling); + Assert.True(model.RawData.ContainsKey("can_defer_billing")); + Assert.Null(model.Discounts); + Assert.True(model.RawData.ContainsKey("discounts")); + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.Filter); + Assert.True(model.RawData.ContainsKey("filter")); + Assert.Null(model.FixedFeeQuantityTransitions); + Assert.True(model.RawData.ContainsKey("fixed_fee_quantity_transitions")); + Assert.Null(model.MaximumAmount); + Assert.True(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.True(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + Assert.Null(model.UsageCustomerIDs); + Assert.True(model.RawData.ContainsKey("usage_customer_ids")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::Add + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + AllocationPrice = null, + CanDeferBilling = null, + Discounts = null, + EndDate = null, + ExternalPriceID = null, + Filter = null, + FixedFeeQuantityTransitions = null, + MaximumAmount = null, + MinimumAmount = null, + Price = null, + PriceID = null, + UsageCustomerIDs = null, + }; + + model.Validate(); + } +} + +public class StartDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::StartDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::StartDate value = new(BillingCycleRelativeDate.StartOfTerm); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::StartDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::StartDate value = new(BillingCycleRelativeDate.StartOfTerm); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class DiscountTest : TestBase +{ + [Fact] + public void AmountValidationWorks() + { + Subscriptions::Discount value = new(new Subscriptions::Amount(0)); + value.Validate(); + } + + [Fact] + public void PercentageValidationWorks() + { + Subscriptions::Discount value = new(new Subscriptions::Percentage(0.15)); + value.Validate(); + } + + [Fact] + public void UsageValidationWorks() + { + Subscriptions::Discount value = new(new Subscriptions::Usage(2)); + value.Validate(); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + Subscriptions::Discount value = new(new Subscriptions::Amount(0)); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + Subscriptions::Discount value = new(new Subscriptions::Percentage(0.15)); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UsageSerializationRoundtripWorks() + { + Subscriptions::Discount value = new(new Subscriptions::Usage(2)); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class AmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Amount { AmountDiscount = 0 }; + + double expectedAmountDiscount = 0; + JsonElement expectedDiscountType = JsonSerializer.Deserialize("\"amount\""); + + Assert.Equal(expectedAmountDiscount, model.AmountDiscount); + Assert.True(JsonElement.DeepEquals(expectedDiscountType, model.DiscountType)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Amount { AmountDiscount = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Amount { AmountDiscount = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedAmountDiscount = 0; + JsonElement expectedDiscountType = JsonSerializer.Deserialize("\"amount\""); + + Assert.Equal(expectedAmountDiscount, deserialized.AmountDiscount); + Assert.True(JsonElement.DeepEquals(expectedDiscountType, deserialized.DiscountType)); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Amount { AmountDiscount = 0 }; + + model.Validate(); + } +} + +public class PercentageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Percentage { PercentageDiscount = 0.15 }; + + JsonElement expectedDiscountType = JsonSerializer.Deserialize( + "\"percentage\"" + ); + double expectedPercentageDiscount = 0.15; + + Assert.True(JsonElement.DeepEquals(expectedDiscountType, model.DiscountType)); + Assert.Equal(expectedPercentageDiscount, model.PercentageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Percentage { PercentageDiscount = 0.15 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Percentage { PercentageDiscount = 0.15 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + JsonElement expectedDiscountType = JsonSerializer.Deserialize( + "\"percentage\"" + ); + double expectedPercentageDiscount = 0.15; + + Assert.True(JsonElement.DeepEquals(expectedDiscountType, deserialized.DiscountType)); + Assert.Equal(expectedPercentageDiscount, deserialized.PercentageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Percentage { PercentageDiscount = 0.15 }; + + model.Validate(); + } +} + +public class UsageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Usage { UsageDiscount = 2 }; + + JsonElement expectedDiscountType = JsonSerializer.Deserialize("\"usage\""); + double expectedUsageDiscount = 2; + + Assert.True(JsonElement.DeepEquals(expectedDiscountType, model.DiscountType)); + Assert.Equal(expectedUsageDiscount, model.UsageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Usage { UsageDiscount = 2 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Usage { UsageDiscount = 2 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + JsonElement expectedDiscountType = JsonSerializer.Deserialize("\"usage\""); + double expectedUsageDiscount = 2; + + Assert.True(JsonElement.DeepEquals(expectedDiscountType, deserialized.DiscountType)); + Assert.Equal(expectedUsageDiscount, deserialized.UsageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Usage { UsageDiscount = 2 }; + + model.Validate(); + } +} + +public class EndDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::EndDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::EndDate value = new(BillingCycleRelativeDate.StartOfTerm); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::EndDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::EndDate value = new(BillingCycleRelativeDate.StartOfTerm); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class FixedFeeQuantityTransitionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedQuantity = 5; + + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedQuantity, model.Quantity); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedQuantity = 5; + + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedQuantity, deserialized.Quantity); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::FixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + model.Validate(); + } +} + +public class PriceModelTest : TestBase +{ + [Fact] + public void NewFloatingUnitValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredPrice() + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingPackagePrice() + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMatrixPrice() + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingThresholdTotalAmountValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingThresholdTotalAmountPrice() + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredPackagePrice() + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithMinimumValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredWithMinimumPrice() + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedTieredPrice() + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingPackageWithAllocationValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingPackageWithAllocationPrice() + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithPercentValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingUnitWithPercentPrice() + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithAllocationValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMatrixWithAllocationPrice() + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingTieredWithProrationValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredWithProrationPrice() + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitWithProrationValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingUnitWithProrationPrice() + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedAllocationValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedAllocationPrice() + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingBulkWithProrationValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelGroupedWithMinMaxThresholds() + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNameValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingGroupedTieredPackageValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedTieredPackagePrice() + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackageValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelCumulativeGroupedAllocation() + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingMinimumCompositeValidationWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMinimumCompositePrice() + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelPercent() + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelEventOutput() + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + value.Validate(); + } + + [Fact] + public void NewFloatingUnitSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredPrice() + { + Cadence = NewFloatingTieredPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = NewFloatingBulkPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingPackagePrice() + { + Cadence = NewFloatingPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMatrixPrice() + { + Cadence = NewFloatingMatrixPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingThresholdTotalAmountSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingThresholdTotalAmountPrice() + { + Cadence = NewFloatingThresholdTotalAmountPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredPackagePrice() + { + Cadence = NewFloatingTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithMinimumSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredWithMinimumPrice() + { + Cadence = NewFloatingTieredWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedTieredPrice() + { + Cadence = NewFloatingGroupedTieredPriceCadence.Annual, + Currency = "currency", + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredPackageWithMinimumSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredPackageWithMinimumPrice() + { + Cadence = NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingPackageWithAllocationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingPackageWithAllocationPrice() + { + Cadence = NewFloatingPackageWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithPercentSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingUnitWithPercentPrice() + { + Cadence = NewFloatingUnitWithPercentPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithAllocationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMatrixWithAllocationPrice() + { + Cadence = NewFloatingMatrixWithAllocationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingTieredWithProrationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingTieredWithProrationPrice() + { + Cadence = NewFloatingTieredWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingUnitWithProrationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingUnitWithProrationPrice() + { + Cadence = NewFloatingUnitWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedAllocationPrice() + { + Cadence = NewFloatingGroupedAllocationPriceCadence.Annual, + Currency = "currency", + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingBulkWithProrationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = NewFloatingBulkWithProrationPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedWithProratedMinimumPrice() + { + Cadence = NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedWithMeteredMinimumPrice() + { + Cadence = NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + Currency = "currency", + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelGroupedWithMinMaxThresholds() + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMatrixWithDisplayNameSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMatrixWithDisplayNamePrice() + { + Cadence = NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingGroupedTieredPackageSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingGroupedTieredPackagePrice() + { + Cadence = NewFloatingGroupedTieredPackagePriceCadence.Annual, + Currency = "currency", + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMaxGroupTieredPackageSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMaxGroupTieredPackagePrice() + { + Cadence = NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingScalableMatrixWithUnitPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingScalableMatrixWithTieredPricingPrice() + { + Cadence = NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingCumulativeGroupedBulkSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingCumulativeGroupedBulkPrice() + { + Cadence = NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelCumulativeGroupedAllocation() + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewFloatingMinimumCompositeSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new NewFloatingMinimumCompositePrice() + { + Cadence = NewFloatingMinimumCompositePriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = NewFloatingMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelPercent() + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Subscriptions::PriceModel value = new( + new Subscriptions::PriceModelEventOutput() + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + Subscriptions::PriceModelBulkWithFiltersCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum expectedCadence = + Subscriptions::PriceModelBulkWithFiltersCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = Subscriptions::PriceModelBulkWithFiltersCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceModelBulkWithFiltersBulkWithFiltersConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class PriceModelBulkWithFiltersBulkWithFiltersConfigFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class PriceModelBulkWithFiltersBulkWithFiltersConfigTierTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class PriceModelBulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Annual)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Monthly)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.OneTime)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Custom)] + public void Validation_Works(Subscriptions::PriceModelBulkWithFiltersCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Annual)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Monthly)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.OneTime)] + [InlineData(Subscriptions::PriceModelBulkWithFiltersCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::PriceModelBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelBulkWithFiltersConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::PriceModelBulkWithFiltersConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::PriceModelBulkWithFiltersConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::PriceModelBulkWithFiltersConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::PriceModelBulkWithFiltersConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelGroupedWithMinMaxThresholdsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum< + string, + Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence + > expectedCadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + Subscriptions::PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence + > expectedCadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual; + string expectedCurrency = "currency"; + Subscriptions::PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelGroupedWithMinMaxThresholds + { + Cadence = Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + Currency = "currency", + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceModelGroupedWithMinMaxThresholdsCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Custom)] + public void Validation_Works( + Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Annual)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Monthly)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.OneTime)] + [InlineData(Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class PriceModelGroupedWithMinMaxThresholdsConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::PriceModelGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::PriceModelGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::PriceModelGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::PriceModelGroupedWithMinMaxThresholdsConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelCumulativeGroupedAllocationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum< + string, + Subscriptions::PriceModelCumulativeGroupedAllocationCadence + > expectedCadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual; + Subscriptions::PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::PriceModelCumulativeGroupedAllocationCadence + > expectedCadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual; + Subscriptions::PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelCumulativeGroupedAllocation + { + Cadence = Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceModelCumulativeGroupedAllocationCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Custom)] + public void Validation_Works( + Subscriptions::PriceModelCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Annual)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Monthly)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.OneTime)] + [InlineData(Subscriptions::PriceModelCumulativeGroupedAllocationCadence.Custom)] + public void SerializationRoundtrip_Works( + Subscriptions::PriceModelCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class PriceModelCumulativeGroupedAllocationConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::PriceModelCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::PriceModelCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::PriceModelCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::PriceModelCumulativeGroupedAllocationConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelPercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + Subscriptions::PriceModelPercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::PriceModelPercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelPercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::PriceModelPercentCadence.Annual; + string expectedCurrency = "currency"; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::PriceModelPercentPercentConfig expectedPercentConfig = new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelPercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelPercent + { + Cadence = Subscriptions::PriceModelPercentCadence.Annual, + Currency = "currency", + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceModelPercentCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::PriceModelPercentCadence.Annual)] + [InlineData(Subscriptions::PriceModelPercentCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelPercentCadence.Monthly)] + [InlineData(Subscriptions::PriceModelPercentCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelPercentCadence.OneTime)] + [InlineData(Subscriptions::PriceModelPercentCadence.Custom)] + public void Validation_Works(Subscriptions::PriceModelPercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::PriceModelPercentCadence.Annual)] + [InlineData(Subscriptions::PriceModelPercentCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelPercentCadence.Monthly)] + [InlineData(Subscriptions::PriceModelPercentCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelPercentCadence.OneTime)] + [InlineData(Subscriptions::PriceModelPercentCadence.Custom)] + public void SerializationRoundtrip_Works(Subscriptions::PriceModelPercentCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelPercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelPercentPercentConfig { Percent = 0 }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelPercentPercentConfig { Percent = 0 }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelPercentPercentConfig { Percent = 0 }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelPercentPercentConfig { Percent = 0 }; + + model.Validate(); + } +} + +public class PriceModelPercentConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::PriceModelPercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::PriceModelPercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::PriceModelPercentConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::PriceModelPercentConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + ApiEnum expectedCadence = + Subscriptions::PriceModelEventOutputCadence.Annual; + string expectedCurrency = "currency"; + Subscriptions::PriceModelEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum expectedCadence = + Subscriptions::PriceModelEventOutputCadence.Annual; + string expectedCurrency = "currency"; + Subscriptions::PriceModelEventOutputEventOutputConfig expectedEventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::PriceModelEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelEventOutput + { + Cadence = Subscriptions::PriceModelEventOutputCadence.Annual, + Currency = "currency", + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + }; + + model.Validate(); + } +} + +public class PriceModelEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Annual)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Monthly)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.OneTime)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Custom)] + public void Validation_Works(Subscriptions::PriceModelEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Annual)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.SemiAnnual)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Monthly)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Quarterly)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.OneTime)] + [InlineData(Subscriptions::PriceModelEventOutputCadence.Custom)] + public void SerializationRoundtrip_Works(Subscriptions::PriceModelEventOutputCadence rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class PriceModelEventOutputEventOutputConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::PriceModelEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class PriceModelEventOutputConversionRateConfigTest : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::PriceModelEventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::PriceModelEventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::PriceModelEventOutputConversionRateConfig value = new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::PriceModelEventOutputConversionRateConfig value = new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionPriceIntervalsParamsAddAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentStartDate expectedStartDate = + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment expectedAdjustment = + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + string expectedAdjustmentID = "h74gfhdjvn7ujokd"; + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentEndDate expectedEndDate = + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedAdjustmentID, model.AdjustmentID); + Assert.Equal(expectedEndDate, model.EndDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentStartDate expectedStartDate = + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment expectedAdjustment = + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + string expectedAdjustmentID = "h74gfhdjvn7ujokd"; + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentEndDate expectedEndDate = + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedAdjustmentID, deserialized.AdjustmentID); + Assert.Equal(expectedEndDate, deserialized.EndDate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + AdjustmentID = "h74gfhdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.Adjustment); + Assert.False(model.RawData.ContainsKey("adjustment")); + Assert.Null(model.AdjustmentID); + Assert.False(model.RawData.ContainsKey("adjustment_id")); + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + Adjustment = null, + AdjustmentID = null, + EndDate = null, + }; + + Assert.Null(model.Adjustment); + Assert.True(model.RawData.ContainsKey("adjustment")); + Assert.Null(model.AdjustmentID); + Assert.True(model.RawData.ContainsKey("adjustment_id")); + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustment + { + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + Adjustment = null, + AdjustmentID = null, + EndDate = null, + }; + + model.Validate(); + } +} + +public class SubscriptionPriceIntervalsParamsAddAdjustmentStartDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentStartDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentStartDate value = new( + BillingCycleRelativeDate.StartOfTerm + ); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentStartDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentStartDate value = new( + BillingCycleRelativeDate.StartOfTerm + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionPriceIntervalsParamsAddAdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionPriceIntervalsParamsAddAdjustmentEndDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentEndDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentEndDate value = new( + BillingCycleRelativeDate.StartOfTerm + ); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentEndDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::SubscriptionPriceIntervalsParamsAddAdjustmentEndDate value = new( + BillingCycleRelativeDate.StartOfTerm + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class EditTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + string expectedPriceIntervalID = "sdfs6wdjvn7ujokd"; + long expectedBillingCycleDay = 0; + bool expectedCanDeferBilling = true; + Subscriptions::EditEndDate expectedEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + string expectedFilter = "my_property > 100 AND my_other_property = 'bar'"; + List expectedFixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ]; + Subscriptions::EditStartDate expectedStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedPriceIntervalID, model.PriceIntervalID); + Assert.Equal(expectedBillingCycleDay, model.BillingCycleDay); + Assert.Equal(expectedCanDeferBilling, model.CanDeferBilling); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilter, model.Filter); + Assert.NotNull(model.FixedFeeQuantityTransitions); + Assert.Equal( + expectedFixedFeeQuantityTransitions.Count, + model.FixedFeeQuantityTransitions.Count + ); + for (int i = 0; i < expectedFixedFeeQuantityTransitions.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantityTransitions[i], + model.FixedFeeQuantityTransitions[i] + ); + } + Assert.Equal(expectedStartDate, model.StartDate); + Assert.NotNull(model.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, model.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], model.UsageCustomerIDs[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPriceIntervalID = "sdfs6wdjvn7ujokd"; + long expectedBillingCycleDay = 0; + bool expectedCanDeferBilling = true; + Subscriptions::EditEndDate expectedEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + string expectedFilter = "my_property > 100 AND my_other_property = 'bar'"; + List expectedFixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ]; + Subscriptions::EditStartDate expectedStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedPriceIntervalID, deserialized.PriceIntervalID); + Assert.Equal(expectedBillingCycleDay, deserialized.BillingCycleDay); + Assert.Equal(expectedCanDeferBilling, deserialized.CanDeferBilling); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilter, deserialized.Filter); + Assert.NotNull(deserialized.FixedFeeQuantityTransitions); + Assert.Equal( + expectedFixedFeeQuantityTransitions.Count, + deserialized.FixedFeeQuantityTransitions.Count + ); + for (int i = 0; i < expectedFixedFeeQuantityTransitions.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantityTransitions[i], + deserialized.FixedFeeQuantityTransitions[i] + ); + } + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.NotNull(deserialized.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, deserialized.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], deserialized.UsageCustomerIDs[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + UsageCustomerIDs = ["string"], + }; + + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + UsageCustomerIDs = ["string"], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + UsageCustomerIDs = ["string"], + + // Null should be interpreted as omitted for these properties + StartDate = null, + }; + + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + BillingCycleDay = 0, + CanDeferBilling = true, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "my_property > 100 AND my_other_property = 'bar'", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }, + ], + UsageCustomerIDs = ["string"], + + // Null should be interpreted as omitted for these properties + StartDate = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.BillingCycleDay); + Assert.False(model.RawData.ContainsKey("billing_cycle_day")); + Assert.Null(model.CanDeferBilling); + Assert.False(model.RawData.ContainsKey("can_defer_billing")); + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.Filter); + Assert.False(model.RawData.ContainsKey("filter")); + Assert.Null(model.FixedFeeQuantityTransitions); + Assert.False(model.RawData.ContainsKey("fixed_fee_quantity_transitions")); + Assert.Null(model.UsageCustomerIDs); + Assert.False(model.RawData.ContainsKey("usage_customer_ids")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + BillingCycleDay = null, + CanDeferBilling = null, + EndDate = null, + Filter = null, + FixedFeeQuantityTransitions = null, + UsageCustomerIDs = null, + }; + + Assert.Null(model.BillingCycleDay); + Assert.True(model.RawData.ContainsKey("billing_cycle_day")); + Assert.Null(model.CanDeferBilling); + Assert.True(model.RawData.ContainsKey("can_defer_billing")); + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.Filter); + Assert.True(model.RawData.ContainsKey("filter")); + Assert.Null(model.FixedFeeQuantityTransitions); + Assert.True(model.RawData.ContainsKey("fixed_fee_quantity_transitions")); + Assert.Null(model.UsageCustomerIDs); + Assert.True(model.RawData.ContainsKey("usage_customer_ids")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::Edit + { + PriceIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + BillingCycleDay = null, + CanDeferBilling = null, + EndDate = null, + Filter = null, + FixedFeeQuantityTransitions = null, + UsageCustomerIDs = null, + }; + + model.Validate(); + } +} + +public class EditEndDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::EditEndDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::EditEndDate value = new(BillingCycleRelativeDate.StartOfTerm); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::EditEndDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::EditEndDate value = new(BillingCycleRelativeDate.StartOfTerm); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EditFixedFeeQuantityTransitionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::EditFixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedQuantity = 5; + + Assert.Equal(expectedEffectiveDate, model.EffectiveDate); + Assert.Equal(expectedQuantity, model.Quantity); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::EditFixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::EditFixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + DateTimeOffset expectedEffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedQuantity = 5; + + Assert.Equal(expectedEffectiveDate, deserialized.EffectiveDate); + Assert.Equal(expectedQuantity, deserialized.Quantity); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::EditFixedFeeQuantityTransition + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Quantity = 5, + }; + + model.Validate(); + } +} + +public class EditStartDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::EditStartDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::EditStartDate value = new(BillingCycleRelativeDate.StartOfTerm); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::EditStartDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::EditStartDate value = new(BillingCycleRelativeDate.StartOfTerm); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class EditAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string expectedAdjustmentIntervalID = "sdfs6wdjvn7ujokd"; + Subscriptions::EditAdjustmentEndDate expectedEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + Subscriptions::EditAdjustmentStartDate expectedStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedAdjustmentIntervalID, model.AdjustmentIntervalID); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAdjustmentIntervalID = "sdfs6wdjvn7ujokd"; + Subscriptions::EditAdjustmentEndDate expectedEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + Subscriptions::EditAdjustmentStartDate expectedStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + + Assert.Equal(expectedAdjustmentIntervalID, deserialized.AdjustmentIntervalID); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + StartDate = null, + }; + + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + // Null should be interpreted as omitted for these properties + StartDate = null, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + EndDate = null, + }; + + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::EditAdjustment + { + AdjustmentIntervalID = "sdfs6wdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + + EndDate = null, + }; + + model.Validate(); + } +} + +public class EditAdjustmentEndDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::EditAdjustmentEndDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::EditAdjustmentEndDate value = new(BillingCycleRelativeDate.StartOfTerm); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::EditAdjustmentEndDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::EditAdjustmentEndDate value = new(BillingCycleRelativeDate.StartOfTerm); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class EditAdjustmentStartDateTest : TestBase +{ + [Fact] + public void DateTimeValidationWorks() + { + Subscriptions::EditAdjustmentStartDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + value.Validate(); + } + + [Fact] + public void BillingCycleRelativeValidationWorks() + { + Subscriptions::EditAdjustmentStartDate value = new(BillingCycleRelativeDate.StartOfTerm); + value.Validate(); + } + + [Fact] + public void DateTimeSerializationRoundtripWorks() + { + Subscriptions::EditAdjustmentStartDate value = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BillingCycleRelativeSerializationRoundtripWorks() + { + Subscriptions::EditAdjustmentStartDate value = new(BillingCycleRelativeDate.StartOfTerm); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionRedeemCouponParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionRedeemCouponParamsTest.cs new file mode 100644 index 00000000..c9d6de53 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionRedeemCouponParamsTest.cs @@ -0,0 +1,141 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionRedeemCouponParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionRedeemCouponParams + { + SubscriptionID = "subscription_id", + ChangeOption = ChangeOption.RequestedDate, + AllowInvoiceCreditOrVoid = true, + ChangeDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"), + CouponID = "coupon_id", + CouponRedemptionCode = "coupon_redemption_code", + }; + + string expectedSubscriptionID = "subscription_id"; + ApiEnum expectedChangeOption = ChangeOption.RequestedDate; + bool expectedAllowInvoiceCreditOrVoid = true; + DateTimeOffset expectedChangeDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"); + string expectedCouponID = "coupon_id"; + string expectedCouponRedemptionCode = "coupon_redemption_code"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedChangeOption, parameters.ChangeOption); + Assert.Equal(expectedAllowInvoiceCreditOrVoid, parameters.AllowInvoiceCreditOrVoid); + Assert.Equal(expectedChangeDate, parameters.ChangeDate); + Assert.Equal(expectedCouponID, parameters.CouponID); + Assert.Equal(expectedCouponRedemptionCode, parameters.CouponRedemptionCode); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionRedeemCouponParams + { + SubscriptionID = "subscription_id", + ChangeOption = ChangeOption.RequestedDate, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.ChangeDate); + Assert.False(parameters.RawBodyData.ContainsKey("change_date")); + Assert.Null(parameters.CouponID); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_id")); + Assert.Null(parameters.CouponRedemptionCode); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_redemption_code")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionRedeemCouponParams + { + SubscriptionID = "subscription_id", + ChangeOption = ChangeOption.RequestedDate, + + AllowInvoiceCreditOrVoid = null, + ChangeDate = null, + CouponID = null, + CouponRedemptionCode = null, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.ChangeDate); + Assert.False(parameters.RawBodyData.ContainsKey("change_date")); + Assert.Null(parameters.CouponID); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_id")); + Assert.Null(parameters.CouponRedemptionCode); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_redemption_code")); + } +} + +public class ChangeOptionTest : TestBase +{ + [Theory] + [InlineData(ChangeOption.RequestedDate)] + [InlineData(ChangeOption.EndOfSubscriptionTerm)] + [InlineData(ChangeOption.Immediate)] + public void Validation_Works(ChangeOption rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ChangeOption.RequestedDate)] + [InlineData(ChangeOption.EndOfSubscriptionTerm)] + [InlineData(ChangeOption.Immediate)] + public void SerializationRoundtrip_Works(ChangeOption rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsTest.cs new file mode 100644 index 00000000..454477e3 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsTest.cs @@ -0,0 +1,21146 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionSchedulePlanChangeParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new Subscriptions::SubscriptionSchedulePlanChangeParams + { + SubscriptionID = "subscription_id", + ChangeOption = + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate, + AddAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AlignBillingWithPlanChangeDate = true, + AutoCollection = true, + BillingCycleAlignment = Subscriptions::BillingCycleAlignment.Unchanged, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + ChangeDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"), + CouponRedemptionCode = "coupon_redemption_code", + CreditsOverageRate = 0, + DefaultInvoiceMemo = "default_invoice_memo", + ExternalPlanID = "ZMwNQefe7J3ecf7W", + Filter = "my_property > 100 AND my_other_property = 'bar'", + InitialPhaseOrder = 2, + InvoicingThreshold = "10.00", + NetTerms = 0, + PerCreditOverageAmount = 0, + PlanID = "ZMwNQefe7J3ecf7W", + PlanVersionNumber = 0, + PriceOverrides = [JsonSerializer.Deserialize("{}")], + RemoveAdjustments = [new("h74gfhdjvn7ujokd")], + RemovePrices = + [ + new() { ExternalPriceID = "external_price_id", PriceID = "h74gfhdjvn7ujokd" }, + ], + ReplaceAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }, + ], + ReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }, + ], + TrialDurationDays = 0, + UsageCustomerIDs = ["string"], + }; + + string expectedSubscriptionID = "subscription_id"; + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption + > expectedChangeOption = + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate; + List expectedAddAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + List expectedAddPrices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAlignBillingWithPlanChangeDate = true; + bool expectedAutoCollection = true; + ApiEnum expectedBillingCycleAlignment = + Subscriptions::BillingCycleAlignment.Unchanged; + BillingCycleAnchorConfiguration expectedBillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }; + DateTimeOffset expectedChangeDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"); + string expectedCouponRedemptionCode = "coupon_redemption_code"; + double expectedCreditsOverageRate = 0; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + string expectedExternalPlanID = "ZMwNQefe7J3ecf7W"; + string expectedFilter = "my_property > 100 AND my_other_property = 'bar'"; + long expectedInitialPhaseOrder = 2; + string expectedInvoicingThreshold = "10.00"; + long expectedNetTerms = 0; + double expectedPerCreditOverageAmount = 0; + string expectedPlanID = "ZMwNQefe7J3ecf7W"; + long expectedPlanVersionNumber = 0; + List expectedPriceOverrides = [JsonSerializer.Deserialize("{}")]; + List expectedRemoveAdjustments = + [ + new("h74gfhdjvn7ujokd"), + ]; + List expectedRemovePrices = + [ + new() { ExternalPriceID = "external_price_id", PriceID = "h74gfhdjvn7ujokd" }, + ]; + List expectedReplaceAdjustments = + [ + new() + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }, + ]; + List expectedReplacePrices = + [ + new() + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }, + ]; + long expectedTrialDurationDays = 0; + List expectedUsageCustomerIDs = ["string"]; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedChangeOption, parameters.ChangeOption); + Assert.NotNull(parameters.AddAdjustments); + Assert.Equal(expectedAddAdjustments.Count, parameters.AddAdjustments.Count); + for (int i = 0; i < expectedAddAdjustments.Count; i++) + { + Assert.Equal(expectedAddAdjustments[i], parameters.AddAdjustments[i]); + } + Assert.NotNull(parameters.AddPrices); + Assert.Equal(expectedAddPrices.Count, parameters.AddPrices.Count); + for (int i = 0; i < expectedAddPrices.Count; i++) + { + Assert.Equal(expectedAddPrices[i], parameters.AddPrices[i]); + } + Assert.Equal( + expectedAlignBillingWithPlanChangeDate, + parameters.AlignBillingWithPlanChangeDate + ); + Assert.Equal(expectedAutoCollection, parameters.AutoCollection); + Assert.Equal(expectedBillingCycleAlignment, parameters.BillingCycleAlignment); + Assert.Equal( + expectedBillingCycleAnchorConfiguration, + parameters.BillingCycleAnchorConfiguration + ); + Assert.Equal(expectedChangeDate, parameters.ChangeDate); + Assert.Equal(expectedCouponRedemptionCode, parameters.CouponRedemptionCode); + Assert.Equal(expectedCreditsOverageRate, parameters.CreditsOverageRate); + Assert.Equal(expectedDefaultInvoiceMemo, parameters.DefaultInvoiceMemo); + Assert.Equal(expectedExternalPlanID, parameters.ExternalPlanID); + Assert.Equal(expectedFilter, parameters.Filter); + Assert.Equal(expectedInitialPhaseOrder, parameters.InitialPhaseOrder); + Assert.Equal(expectedInvoicingThreshold, parameters.InvoicingThreshold); + Assert.Equal(expectedNetTerms, parameters.NetTerms); + Assert.Equal(expectedPerCreditOverageAmount, parameters.PerCreditOverageAmount); + Assert.Equal(expectedPlanID, parameters.PlanID); + Assert.Equal(expectedPlanVersionNumber, parameters.PlanVersionNumber); + Assert.NotNull(parameters.PriceOverrides); + Assert.Equal(expectedPriceOverrides.Count, parameters.PriceOverrides.Count); + for (int i = 0; i < expectedPriceOverrides.Count; i++) + { + Assert.True( + JsonElement.DeepEquals(expectedPriceOverrides[i], parameters.PriceOverrides[i]) + ); + } + Assert.NotNull(parameters.RemoveAdjustments); + Assert.Equal(expectedRemoveAdjustments.Count, parameters.RemoveAdjustments.Count); + for (int i = 0; i < expectedRemoveAdjustments.Count; i++) + { + Assert.Equal(expectedRemoveAdjustments[i], parameters.RemoveAdjustments[i]); + } + Assert.NotNull(parameters.RemovePrices); + Assert.Equal(expectedRemovePrices.Count, parameters.RemovePrices.Count); + for (int i = 0; i < expectedRemovePrices.Count; i++) + { + Assert.Equal(expectedRemovePrices[i], parameters.RemovePrices[i]); + } + Assert.NotNull(parameters.ReplaceAdjustments); + Assert.Equal(expectedReplaceAdjustments.Count, parameters.ReplaceAdjustments.Count); + for (int i = 0; i < expectedReplaceAdjustments.Count; i++) + { + Assert.Equal(expectedReplaceAdjustments[i], parameters.ReplaceAdjustments[i]); + } + Assert.NotNull(parameters.ReplacePrices); + Assert.Equal(expectedReplacePrices.Count, parameters.ReplacePrices.Count); + for (int i = 0; i < expectedReplacePrices.Count; i++) + { + Assert.Equal(expectedReplacePrices[i], parameters.ReplacePrices[i]); + } + Assert.Equal(expectedTrialDurationDays, parameters.TrialDurationDays); + Assert.NotNull(parameters.UsageCustomerIDs); + Assert.Equal(expectedUsageCustomerIDs.Count, parameters.UsageCustomerIDs.Count); + for (int i = 0; i < expectedUsageCustomerIDs.Count; i++) + { + Assert.Equal(expectedUsageCustomerIDs[i], parameters.UsageCustomerIDs[i]); + } + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new Subscriptions::SubscriptionSchedulePlanChangeParams + { + SubscriptionID = "subscription_id", + ChangeOption = + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.AlignBillingWithPlanChangeDate); + Assert.False(parameters.RawBodyData.ContainsKey("align_billing_with_plan_change_date")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.BillingCycleAlignment); + Assert.False(parameters.RawBodyData.ContainsKey("billing_cycle_alignment")); + Assert.Null(parameters.BillingCycleAnchorConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("billing_cycle_anchor_configuration")); + Assert.Null(parameters.ChangeDate); + Assert.False(parameters.RawBodyData.ContainsKey("change_date")); + Assert.Null(parameters.CouponRedemptionCode); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_redemption_code")); + Assert.Null(parameters.CreditsOverageRate); + Assert.False(parameters.RawBodyData.ContainsKey("credits_overage_rate")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Filter); + Assert.False(parameters.RawBodyData.ContainsKey("filter")); + Assert.Null(parameters.InitialPhaseOrder); + Assert.False(parameters.RawBodyData.ContainsKey("initial_phase_order")); + Assert.Null(parameters.InvoicingThreshold); + Assert.False(parameters.RawBodyData.ContainsKey("invoicing_threshold")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + Assert.Null(parameters.PerCreditOverageAmount); + Assert.False(parameters.RawBodyData.ContainsKey("per_credit_overage_amount")); + Assert.Null(parameters.PlanID); + Assert.False(parameters.RawBodyData.ContainsKey("plan_id")); + Assert.Null(parameters.PlanVersionNumber); + Assert.False(parameters.RawBodyData.ContainsKey("plan_version_number")); + Assert.Null(parameters.PriceOverrides); + Assert.False(parameters.RawBodyData.ContainsKey("price_overrides")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.TrialDurationDays); + Assert.False(parameters.RawBodyData.ContainsKey("trial_duration_days")); + Assert.Null(parameters.UsageCustomerIDs); + Assert.False(parameters.RawBodyData.ContainsKey("usage_customer_ids")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new Subscriptions::SubscriptionSchedulePlanChangeParams + { + SubscriptionID = "subscription_id", + ChangeOption = + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate, + + AddAdjustments = null, + AddPrices = null, + AlignBillingWithPlanChangeDate = null, + AutoCollection = null, + BillingCycleAlignment = null, + BillingCycleAnchorConfiguration = null, + ChangeDate = null, + CouponRedemptionCode = null, + CreditsOverageRate = null, + DefaultInvoiceMemo = null, + ExternalPlanID = null, + Filter = null, + InitialPhaseOrder = null, + InvoicingThreshold = null, + NetTerms = null, + PerCreditOverageAmount = null, + PlanID = null, + PlanVersionNumber = null, + PriceOverrides = null, + RemoveAdjustments = null, + RemovePrices = null, + ReplaceAdjustments = null, + ReplacePrices = null, + TrialDurationDays = null, + UsageCustomerIDs = null, + }; + + Assert.Null(parameters.AddAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("add_adjustments")); + Assert.Null(parameters.AddPrices); + Assert.False(parameters.RawBodyData.ContainsKey("add_prices")); + Assert.Null(parameters.AlignBillingWithPlanChangeDate); + Assert.False(parameters.RawBodyData.ContainsKey("align_billing_with_plan_change_date")); + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.BillingCycleAlignment); + Assert.False(parameters.RawBodyData.ContainsKey("billing_cycle_alignment")); + Assert.Null(parameters.BillingCycleAnchorConfiguration); + Assert.False(parameters.RawBodyData.ContainsKey("billing_cycle_anchor_configuration")); + Assert.Null(parameters.ChangeDate); + Assert.False(parameters.RawBodyData.ContainsKey("change_date")); + Assert.Null(parameters.CouponRedemptionCode); + Assert.False(parameters.RawBodyData.ContainsKey("coupon_redemption_code")); + Assert.Null(parameters.CreditsOverageRate); + Assert.False(parameters.RawBodyData.ContainsKey("credits_overage_rate")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.ExternalPlanID); + Assert.False(parameters.RawBodyData.ContainsKey("external_plan_id")); + Assert.Null(parameters.Filter); + Assert.False(parameters.RawBodyData.ContainsKey("filter")); + Assert.Null(parameters.InitialPhaseOrder); + Assert.False(parameters.RawBodyData.ContainsKey("initial_phase_order")); + Assert.Null(parameters.InvoicingThreshold); + Assert.False(parameters.RawBodyData.ContainsKey("invoicing_threshold")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + Assert.Null(parameters.PerCreditOverageAmount); + Assert.False(parameters.RawBodyData.ContainsKey("per_credit_overage_amount")); + Assert.Null(parameters.PlanID); + Assert.False(parameters.RawBodyData.ContainsKey("plan_id")); + Assert.Null(parameters.PlanVersionNumber); + Assert.False(parameters.RawBodyData.ContainsKey("plan_version_number")); + Assert.Null(parameters.PriceOverrides); + Assert.False(parameters.RawBodyData.ContainsKey("price_overrides")); + Assert.Null(parameters.RemoveAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("remove_adjustments")); + Assert.Null(parameters.RemovePrices); + Assert.False(parameters.RawBodyData.ContainsKey("remove_prices")); + Assert.Null(parameters.ReplaceAdjustments); + Assert.False(parameters.RawBodyData.ContainsKey("replace_adjustments")); + Assert.Null(parameters.ReplacePrices); + Assert.False(parameters.RawBodyData.ContainsKey("replace_prices")); + Assert.Null(parameters.TrialDurationDays); + Assert.False(parameters.RawBodyData.ContainsKey("trial_duration_days")); + Assert.Null(parameters.UsageCustomerIDs); + Assert.False(parameters.RawBodyData.ContainsKey("usage_customer_ids")); + } +} + +public class SubscriptionSchedulePlanChangeParamsChangeOptionTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate)] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.EndOfSubscriptionTerm + )] + [InlineData(Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.Immediate)] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate)] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.EndOfSubscriptionTerm + )] + [InlineData(Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption.Immediate)] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment expectedAdjustment = + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedPlanPhaseOrder = 0; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment expectedAdjustment = + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + long expectedPlanPhaseOrder = 0; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PlanPhaseOrder = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + }; + + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + + EndDate = null, + PlanPhaseOrder = null, + StartDate = null, + }; + + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.StartDate); + Assert.True(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + + EndDate = null, + PlanPhaseOrder = null, + StartDate = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalPriceID = "external_price_id"; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + long expectedPlanPhaseOrder = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice expectedPrice = + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPlanPhaseOrder, model.PlanPhaseOrder); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + Assert.Equal(expectedStartDate, model.StartDate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + string expectedExternalPriceID = "external_price_id"; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + long expectedPlanPhaseOrder = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice expectedPrice = + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPlanPhaseOrder, deserialized.PlanPhaseOrder); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + Assert.Equal(expectedStartDate, deserialized.StartDate); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExternalPriceID = "external_price_id", + MaximumAmount = "1.23", + MinimumAmount = "1.23", + PlanPhaseOrder = 0, + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice { }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + Assert.Null(model.EndDate); + Assert.False(model.RawData.ContainsKey("end_date")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.MaximumAmount); + Assert.False(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.False(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.PlanPhaseOrder); + Assert.False(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + Assert.Null(model.StartDate); + Assert.False(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice + { + AllocationPrice = null, + Discounts = null, + EndDate = null, + ExternalPriceID = null, + MaximumAmount = null, + MinimumAmount = null, + PlanPhaseOrder = null, + Price = null, + PriceID = null, + StartDate = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.True(model.RawData.ContainsKey("discounts")); + Assert.Null(model.EndDate); + Assert.True(model.RawData.ContainsKey("end_date")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.MaximumAmount); + Assert.True(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.True(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.PlanPhaseOrder); + Assert.True(model.RawData.ContainsKey("plan_phase_order")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + Assert.Null(model.StartDate); + Assert.True(model.RawData.ContainsKey("start_date")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPrice + { + AllocationPrice = null, + Discounts = null, + EndDate = null, + ExternalPriceID = null, + MaximumAmount = null, + MinimumAmount = null, + PlanPhaseOrder = null, + Price = null, + PriceID = null, + StartDate = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceTest : TestBase +{ + [Fact] + public void NewSubscriptionUnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithPercentValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithProrationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkWithProrationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMinimumCompositeValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithPercentSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithProrationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkWithProrationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMinimumCompositeSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilterTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTierTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadenceTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTierTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig expectedPercentConfig = + new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig expectedPercentConfig = + new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig + { + Percent = 0, + }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig + { + Percent = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig + { + Percent = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig + { + Percent = 0, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class BillingCycleAlignmentTest : TestBase +{ + [Theory] + [InlineData(Subscriptions::BillingCycleAlignment.Unchanged)] + [InlineData(Subscriptions::BillingCycleAlignment.PlanChangeDate)] + [InlineData(Subscriptions::BillingCycleAlignment.StartOfMonth)] + public void Validation_Works(Subscriptions::BillingCycleAlignment rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Subscriptions::BillingCycleAlignment.Unchanged)] + [InlineData(Subscriptions::BillingCycleAlignment.PlanChangeDate)] + [InlineData(Subscriptions::BillingCycleAlignment.StartOfMonth)] + public void SerializationRoundtrip_Works(Subscriptions::BillingCycleAlignment rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsRemoveAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemoveAdjustment + { + AdjustmentID = "h74gfhdjvn7ujokd", + }; + + string expectedAdjustmentID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedAdjustmentID, model.AdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemoveAdjustment + { + AdjustmentID = "h74gfhdjvn7ujokd", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemoveAdjustment + { + AdjustmentID = "h74gfhdjvn7ujokd", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedAdjustmentID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedAdjustmentID, deserialized.AdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemoveAdjustment + { + AdjustmentID = "h74gfhdjvn7ujokd", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsRemovePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + string expectedExternalPriceID = "external_price_id"; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedExternalPriceID = "external_price_id"; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice + { + ExternalPriceID = "external_price_id", + PriceID = "h74gfhdjvn7ujokd", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice { }; + + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice { }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice + { + ExternalPriceID = null, + PriceID = null, + }; + + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsRemovePrice + { + ExternalPriceID = null, + PriceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplaceAdjustmentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment expectedAdjustment = + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedAdjustment, model.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, model.ReplacesAdjustmentID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment expectedAdjustment = + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }; + string expectedReplacesAdjustmentID = "replaces_adjustment_id"; + + Assert.Equal(expectedAdjustment, deserialized.Adjustment); + Assert.Equal(expectedReplacesAdjustmentID, deserialized.ReplacesAdjustmentID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustment + { + Adjustment = new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + }, + ReplacesAdjustmentID = "replaces_adjustment_id", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustmentTest : TestBase +{ + [Fact] + public void NewPercentageDiscountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewUsageDiscountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewAmountDiscountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewMaximumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + value.Validate(); + } + + [Fact] + public void NewPercentageDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewPercentageDiscount() + { + AdjustmentType = NewPercentageDiscountAdjustmentType.PercentageDiscount, + PercentageDiscount = 0, + AppliesToAll = NewPercentageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewPercentageDiscountFilterField.PriceID, + Operator = NewPercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewPercentageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewUsageDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewUsageDiscount() + { + AdjustmentType = NewUsageDiscountAdjustmentType.UsageDiscount, + UsageDiscount = 0, + AppliesToAll = NewUsageDiscountAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewUsageDiscountFilterField.PriceID, + Operator = NewUsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewUsageDiscountPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewAmountDiscountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewAmountDiscount() + { + AdjustmentType = NewAmountDiscountAdjustmentType.AmountDiscount, + AmountDiscount = "amount_discount", + AppliesToAll = AppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewAmountDiscountFilterField.PriceID, + Operator = NewAmountDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = PriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewMinimum() + { + AdjustmentType = NewMinimumAdjustmentType.Minimum, + ItemID = "item_id", + MinimumAmount = "minimum_amount", + AppliesToAll = NewMinimumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMinimumFilterField.PriceID, + Operator = NewMinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMinimumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewMaximumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value = new( + new NewMaximum() + { + AdjustmentType = NewMaximumAdjustmentType.Maximum, + MaximumAmount = "maximum_amount", + AppliesToAll = NewMaximumAppliesToAll.True, + AppliesToItemIDs = ["item_1", "item_2"], + AppliesToPriceIDs = ["price_1", "price_2"], + Currency = "currency", + Filters = + [ + new() + { + Field = NewMaximumFilterField.PriceID, + Operator = NewMaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PriceType = NewMaximumPriceType.Usage, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePriceTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + string expectedReplacesPriceID = "replaces_price_id"; + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 2; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice expectedPrice = + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedReplacesPriceID, model.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, model.AllocationPrice); + Assert.NotNull(model.Discounts); + Assert.Equal(expectedDiscounts.Count, model.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], model.Discounts[i]); + } + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedMaximumAmount, model.MaximumAmount); + Assert.Equal(expectedMinimumAmount, model.MinimumAmount); + Assert.Equal(expectedPrice, model.Price); + Assert.Equal(expectedPriceID, model.PriceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedReplacesPriceID = "replaces_price_id"; + NewAllocationPrice expectedAllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }; + List expectedDiscounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ]; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 2; + string expectedMaximumAmount = "1.23"; + string expectedMinimumAmount = "1.23"; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice expectedPrice = + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + string expectedPriceID = "h74gfhdjvn7ujokd"; + + Assert.Equal(expectedReplacesPriceID, deserialized.ReplacesPriceID); + Assert.Equal(expectedAllocationPrice, deserialized.AllocationPrice); + Assert.NotNull(deserialized.Discounts); + Assert.Equal(expectedDiscounts.Count, deserialized.Discounts.Count); + for (int i = 0; i < expectedDiscounts.Count; i++) + { + Assert.Equal(expectedDiscounts[i], deserialized.Discounts[i]); + } + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedMaximumAmount, deserialized.MaximumAmount); + Assert.Equal(expectedMinimumAmount, deserialized.MinimumAmount); + Assert.Equal(expectedPrice, deserialized.Price); + Assert.Equal(expectedPriceID, deserialized.PriceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + Discounts = + [ + new() + { + DiscountType = Subscriptions::DiscountType.Percentage, + AmountDiscount = "amount_discount", + PercentageDiscount = 0.15, + UsageDiscount = 0, + }, + ], + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 2, + MaximumAmount = "1.23", + MinimumAmount = "1.23", + Price = new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + PriceID = "h74gfhdjvn7ujokd", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + }; + + Assert.Null(model.AllocationPrice); + Assert.False(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.False(model.RawData.ContainsKey("discounts")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.MaximumAmount); + Assert.False(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.False(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.Price); + Assert.False(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.False(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + Discounts = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + MaximumAmount = null, + MinimumAmount = null, + Price = null, + PriceID = null, + }; + + Assert.Null(model.AllocationPrice); + Assert.True(model.RawData.ContainsKey("allocation_price")); + Assert.Null(model.Discounts); + Assert.True(model.RawData.ContainsKey("discounts")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.MaximumAmount); + Assert.True(model.RawData.ContainsKey("maximum_amount")); + Assert.Null(model.MinimumAmount); + Assert.True(model.RawData.ContainsKey("minimum_amount")); + Assert.Null(model.Price); + Assert.True(model.RawData.ContainsKey("price")); + Assert.Null(model.PriceID); + Assert.True(model.RawData.ContainsKey("price_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePrice + { + ReplacesPriceID = "replaces_price_id", + + AllocationPrice = null, + Discounts = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + MaximumAmount = null, + MinimumAmount = null, + Price = null, + PriceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceTest : TestBase +{ + [Fact] + public void NewSubscriptionUnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void BulkWithFiltersValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithPercentValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void TieredWithProrationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitWithProrationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionBulkWithProrationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void GroupedWithMinMaxThresholdsValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void CumulativeGroupedAllocationValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionMinimumCompositeValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void PercentValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void EventOutputValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + value.Validate(); + } + + [Fact] + public void NewSubscriptionUnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPriceModelType.Tiered, + Name = "Annual fee", + TieredConfig = new() + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkPrice() + { + BulkConfig = new([new() { UnitAmount = "unit_amount", MaximumUnits = 0 }]), + Cadence = Subscriptions::NewSubscriptionBulkPriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::ModelType.Bulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void BulkWithFiltersSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters() + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionPackagePriceModelType.Package, + Name = "Annual fee", + PackageConfig = new() { PackageAmount = "package_amount", PackageSize = 1 }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixPriceCadence.Annual, + ItemID = "item_id", + MatrixConfig = new() + { + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = Subscriptions::NewSubscriptionMatrixPriceModelType.Matrix, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionThresholdTotalAmountSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionThresholdTotalAmountPrice() + { + Cadence = Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + Name = "Annual fee", + ThresholdTotalAmountConfig = new() + { + ConsumptionTable = + [ + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + new() { Threshold = "threshold", TotalAmount = "total_amount" }, + ], + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackagePriceCadence.Annual, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionTieredPackagePriceModelType.TieredPackage, + Name = "Annual fee", + TieredPackageConfig = new() + { + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredWithMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + Name = "Annual fee", + TieredWithMinimumConfig = new() + { + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + new() + { + MinimumAmount = "minimum_amount", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + HideZeroAmountTiers = true, + Prorate = true, + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPriceCadence.Annual, + GroupedTieredConfig = new() + { + GroupingKey = "x", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = Subscriptions::NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionTieredPackageWithMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice() + { + Cadence = Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + Name = "Annual fee", + TieredPackageWithMinimumConfig = new() + { + PackageSize = 0, + Tiers = + [ + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + new() + { + MinimumAmount = "minimum_amount", + PerUnit = "per_unit", + TierLowerBound = "tier_lower_bound", + }, + ], + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionPackageWithAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionPackageWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + Name = "Annual fee", + PackageWithAllocationConfig = new() + { + Allocation = "allocation", + PackageAmount = "package_amount", + PackageSize = "package_size", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithPercentSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithPercentPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithPercentPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + Name = "Annual fee", + UnitWithPercentConfig = new() { Percent = "percent", UnitAmount = "unit_amount" }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + ItemID = "item_id", + MatrixWithAllocationConfig = new() + { + Allocation = "allocation", + DefaultUnitAmount = "default_unit_amount", + Dimensions = ["string"], + MatrixValues = + [ + new() { DimensionValues = ["string"], UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredWithProrationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionUnitWithProrationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionUnitWithProrationPrice() + { + Cadence = Subscriptions::NewSubscriptionUnitWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + Name = "Annual fee", + UnitWithProrationConfig = new("unit_amount"), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedAllocationPrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedAllocationPriceCadence.Annual, + GroupedAllocationConfig = new() + { + Allocation = "allocation", + GroupingKey = "x", + OverageUnitRate = "overage_unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionBulkWithProrationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionBulkWithProrationPrice() + { + BulkWithProrationConfig = new( + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ] + ), + Cadence = Subscriptions::NewSubscriptionBulkWithProrationPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithProratedMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + GroupedWithProratedMinimumConfig = new() + { + GroupingKey = "x", + Minimum = "minimum", + UnitRate = "unit_rate", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedWithMeteredMinimumSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice() + { + Cadence = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + GroupedWithMeteredMinimumConfig = new() + { + GroupingKey = "x", + MinimumUnitAmount = "minimum_unit_amount", + PricingKey = "pricing_key", + ScalingFactors = + [ + new() + { + ScalingFactorValue = "scaling_factor", + ScalingValue = "scaling_value", + }, + ], + ScalingKey = "scaling_key", + UnitAmounts = + [ + new() { PricingValue = "pricing_value", UnitAmountValue = "unit_amount" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedWithMinMaxThresholdsSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMatrixWithDisplayNameSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice() + { + Cadence = Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + ItemID = "item_id", + MatrixWithDisplayNameConfig = new() + { + Dimension = "dimension", + UnitAmounts = + [ + new() + { + DimensionValue = "dimension_value", + DisplayName = "display_name", + UnitAmount = "unit_amount", + }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionGroupedTieredPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionGroupedTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + GroupedTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + new() { PerUnit = "per_unit", TierLowerBound = "tier_lower_bound" }, + ], + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMaxGroupTieredPackageSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice() + { + Cadence = Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + ItemID = "item_id", + MaxGroupTieredPackageConfig = new() + { + GroupingKey = "x", + PackageSize = "package_size", + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + }, + ModelType = + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithUnitPricingSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + Name = "Annual fee", + ScalableMatrixWithUnitPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + UnitPrice = "unit_price", + Prorate = true, + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionScalableMatrixWithTieredPricingSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice() + { + Cadence = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + Name = "Annual fee", + ScalableMatrixWithTieredPricingConfig = new() + { + FirstDimension = "first_dimension", + MatrixScalingFactors = + [ + new() + { + FirstDimensionValue = "first_dimension_value", + ScalingFactor = "scaling_factor", + SecondDimensionValue = "second_dimension_value", + }, + ], + Tiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ], + SecondDimension = "second_dimension", + }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionCumulativeGroupedBulkSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice() + { + Cadence = Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + CumulativeGroupedBulkConfig = new() + { + DimensionValues = + [ + new() + { + GroupingKey = "x", + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }, + ], + Group = "group", + }, + ItemID = "item_id", + ModelType = + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void CumulativeGroupedAllocationSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void NewSubscriptionMinimumCompositeSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::NewSubscriptionMinimumCompositePrice() + { + Cadence = Subscriptions::NewSubscriptionMinimumCompositePriceCadence.Annual, + ItemID = "item_id", + MinimumConfig = new() { MinimumAmount = "minimum_amount", Prorated = true }, + ModelType = Subscriptions::NewSubscriptionMinimumCompositePriceModelType.Minimum, + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void EventOutputSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePrice value = new( + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput() + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, model.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig expectedBulkWithFiltersConfig = + new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"bulk_with_filters\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedBulkWithFiltersConfig, deserialized.BulkWithFiltersConfig); + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + { + BulkWithFiltersConfig = new() + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }, + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedFilters = + [ + new() { PropertyKey = "x", PropertyValue = "x" }, + ]; + List expectedTiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ]; + + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + { + Filters = [new() { PropertyKey = "x", PropertyValue = "x" }], + Tiers = + [ + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + new() { UnitAmount = "unit_amount", TierLowerBound = "tier_lower_bound" }, + ], + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "x"; + string expectedPropertyValue = "x"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + { + PropertyKey = "x", + PropertyValue = "x", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + string expectedTierLowerBound = "tier_lower_bound"; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + TierLowerBound = "tier_lower_bound", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + Assert.Null(model.TierLowerBound); + Assert.False(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + Assert.Null(model.TierLowerBound); + Assert.True(model.RawData.ContainsKey("tier_lower_bound")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + { + UnitAmount = "unit_amount", + + TierLowerBound = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedTieredWithProrationConfig, model.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"tiered_with_proration\"" + ); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig expectedTieredWithProrationConfig = + new([new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }]); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedTieredWithProrationConfig, deserialized.TieredWithProrationConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + TieredWithProrationConfig = new( + [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }] + ), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }, + ]; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + { + Tiers = [new() { TierLowerBound = "tier_lower_bound", UnitAmount = "unit_amount" }], + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTierTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, model.TierLowerBound); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedTierLowerBound = "tier_lower_bound"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedTierLowerBound, deserialized.TierLowerBound); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + { + TierLowerBound = "tier_lower_bound", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + model.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig expectedGroupedWithMinMaxThresholdsConfig = + new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedGroupedWithMinMaxThresholdsConfig, + deserialized.GroupedWithMinMaxThresholdsConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + GroupedWithMinMaxThresholdsConfig = new() + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedMaximumCharge, model.MaximumCharge); + Assert.Equal(expectedMinimumCharge, model.MinimumCharge); + Assert.Equal(expectedPerUnitRate, model.PerUnitRate); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedGroupingKey = "x"; + string expectedMaximumCharge = "maximum_charge"; + string expectedMinimumCharge = "minimum_charge"; + string expectedPerUnitRate = "per_unit_rate"; + + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedMaximumCharge, deserialized.MaximumCharge); + Assert.Equal(expectedMinimumCharge, deserialized.MinimumCharge); + Assert.Equal(expectedPerUnitRate, deserialized.PerUnitRate); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + { + GroupingKey = "x", + MaximumCharge = "maximum_charge", + MinimumCharge = "minimum_charge", + PerUnitRate = "per_unit_rate", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + model.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig expectedCumulativeGroupedAllocationConfig = + new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal( + expectedCumulativeGroupedAllocationConfig, + deserialized.CumulativeGroupedAllocationConfig + ); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + CumulativeGroupedAllocationConfig = new() + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadenceTest + : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, model.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, model.GroupAllocation); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedCumulativeAllocation = "cumulative_allocation"; + string expectedGroupAllocation = "group_allocation"; + string expectedGroupingKey = "x"; + string expectedUnitAmount = "unit_amount"; + + Assert.Equal(expectedCumulativeAllocation, deserialized.CumulativeAllocation); + Assert.Equal(expectedGroupAllocation, deserialized.GroupAllocation); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + { + CumulativeAllocation = "cumulative_allocation", + GroupAllocation = "group_allocation", + GroupingKey = "x", + UnitAmount = "unit_amount", + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig expectedPercentConfig = + new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedPercentConfig, model.PercentConfig); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"percent\""); + string expectedName = "Annual fee"; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig expectedPercentConfig = + new(0); + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedPercentConfig, deserialized.PercentConfig); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercent + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + ItemID = "item_id", + Name = "Annual fee", + PercentConfig = new(0), + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadenceTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig + { + Percent = 0, + }; + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, model.Percent); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig + { + Percent = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig + { + Percent = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + double expectedPercent = 0; + + Assert.Equal(expectedPercent, deserialized.Percent); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig + { + Percent = 0, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, model.Cadence); + Assert.Equal(expectedEventOutputConfig, model.EventOutputConfig); + Assert.Equal(expectedItemID, model.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, model.ModelType)); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedBillableMetricID, model.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, model.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, model.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, model.ConversionRate); + Assert.Equal(expectedConversionRateConfig, model.ConversionRateConfig); + Assert.Equal(expectedCurrency, model.Currency); + Assert.Equal(expectedDimensionalPriceConfiguration, model.DimensionalPriceConfiguration); + Assert.Equal(expectedExternalPriceID, model.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, model.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, model.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, model.InvoicingCycleConfiguration); + Assert.NotNull(model.Metadata); + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, model.ReferenceID); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > expectedCadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig expectedEventOutputConfig = + new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + string expectedItemID = "item_id"; + JsonElement expectedModelType = JsonSerializer.Deserialize("\"event_output\""); + string expectedName = "Annual fee"; + string expectedBillableMetricID = "billable_metric_id"; + bool expectedBilledInAdvance = true; + NewBillingCycleConfiguration expectedBillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + double expectedConversionRate = 0; + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig expectedConversionRateConfig = + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }; + string expectedCurrency = "currency"; + NewDimensionalPriceConfiguration expectedDimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }; + string expectedExternalPriceID = "external_price_id"; + double expectedFixedPriceQuantity = 0; + string expectedInvoiceGroupingKey = "x"; + NewBillingCycleConfiguration expectedInvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + string expectedReferenceID = "reference_id"; + + Assert.Equal(expectedCadence, deserialized.Cadence); + Assert.Equal(expectedEventOutputConfig, deserialized.EventOutputConfig); + Assert.Equal(expectedItemID, deserialized.ItemID); + Assert.True(JsonElement.DeepEquals(expectedModelType, deserialized.ModelType)); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedBillableMetricID, deserialized.BillableMetricID); + Assert.Equal(expectedBilledInAdvance, deserialized.BilledInAdvance); + Assert.Equal(expectedBillingCycleConfiguration, deserialized.BillingCycleConfiguration); + Assert.Equal(expectedConversionRate, deserialized.ConversionRate); + Assert.Equal(expectedConversionRateConfig, deserialized.ConversionRateConfig); + Assert.Equal(expectedCurrency, deserialized.Currency); + Assert.Equal( + expectedDimensionalPriceConfiguration, + deserialized.DimensionalPriceConfiguration + ); + Assert.Equal(expectedExternalPriceID, deserialized.ExternalPriceID); + Assert.Equal(expectedFixedPriceQuantity, deserialized.FixedPriceQuantity); + Assert.Equal(expectedInvoiceGroupingKey, deserialized.InvoiceGroupingKey); + Assert.Equal(expectedInvoicingCycleConfiguration, deserialized.InvoicingCycleConfiguration); + Assert.NotNull(deserialized.Metadata); + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedReferenceID, deserialized.ReferenceID); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + Assert.Null(model.BillableMetricID); + Assert.False(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.False(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.False(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.False(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.False(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.False(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.False(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.False(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.False(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.False(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.False(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.False(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + Assert.Null(model.BillableMetricID); + Assert.True(model.RawData.ContainsKey("billable_metric_id")); + Assert.Null(model.BilledInAdvance); + Assert.True(model.RawData.ContainsKey("billed_in_advance")); + Assert.Null(model.BillingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("billing_cycle_configuration")); + Assert.Null(model.ConversionRate); + Assert.True(model.RawData.ContainsKey("conversion_rate")); + Assert.Null(model.ConversionRateConfig); + Assert.True(model.RawData.ContainsKey("conversion_rate_config")); + Assert.Null(model.Currency); + Assert.True(model.RawData.ContainsKey("currency")); + Assert.Null(model.DimensionalPriceConfiguration); + Assert.True(model.RawData.ContainsKey("dimensional_price_configuration")); + Assert.Null(model.ExternalPriceID); + Assert.True(model.RawData.ContainsKey("external_price_id")); + Assert.Null(model.FixedPriceQuantity); + Assert.True(model.RawData.ContainsKey("fixed_price_quantity")); + Assert.Null(model.InvoiceGroupingKey); + Assert.True(model.RawData.ContainsKey("invoice_grouping_key")); + Assert.Null(model.InvoicingCycleConfiguration); + Assert.True(model.RawData.ContainsKey("invoicing_cycle_configuration")); + Assert.Null(model.Metadata); + Assert.True(model.RawData.ContainsKey("metadata")); + Assert.Null(model.ReferenceID); + Assert.True(model.RawData.ContainsKey("reference_id")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + { + Cadence = + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + EventOutputConfig = new() + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }, + ItemID = "item_id", + Name = "Annual fee", + + BillableMetricID = null, + BilledInAdvance = null, + BillingCycleConfiguration = null, + ConversionRate = null, + ConversionRateConfig = null, + Currency = null, + DimensionalPriceConfiguration = null, + ExternalPriceID = null, + FixedPriceQuantity = null, + InvoiceGroupingKey = null, + InvoicingCycleConfiguration = null, + Metadata = null, + ReferenceID = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadenceTest : TestBase +{ + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Custom + )] + public void Validation_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.SemiAnnual + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Monthly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Quarterly + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.OneTime + )] + [InlineData( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Custom + )] + public void SerializationRoundtrip_Works( + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfigTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, model.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, model.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, model.GroupingKey); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = + JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedUnitRatingKey = "x"; + string expectedDefaultUnitRate = "default_unit_rate"; + string expectedGroupingKey = "grouping_key"; + + Assert.Equal(expectedUnitRatingKey, deserialized.UnitRatingKey); + Assert.Equal(expectedDefaultUnitRate, deserialized.DefaultUnitRate); + Assert.Equal(expectedGroupingKey, deserialized.GroupingKey); + } + + [Fact] + public void Validation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + DefaultUnitRate = "default_unit_rate", + GroupingKey = "grouping_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + Assert.Null(model.DefaultUnitRate); + Assert.False(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.False(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + Assert.Null(model.DefaultUnitRate); + Assert.True(model.RawData.ContainsKey("default_unit_rate")); + Assert.Null(model.GroupingKey); + Assert.True(model.RawData.ContainsKey("grouping_key")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = + new Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + { + UnitRatingKey = "x", + + DefaultUnitRate = null, + GroupingKey = null, + }; + + model.Validate(); + } +} + +public class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfigTest + : TestBase +{ + [Fact] + public void UnitValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + value.Validate(); + } + + [Fact] + public void TieredValidationWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + value.Validate(); + } + + [Fact] + public void UnitSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig value = + new( + new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void TieredSerializationRoundtripWorks() + { + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig value = + new( + new SharedTieredConversionRateConfig() + { + ConversionRateType = ConversionRateType.Tiered, + TieredConfig = new( + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ] + ), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = + JsonSerializer.Deserialize( + element + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionSubscriptionsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionSubscriptionsTest.cs new file mode 100644 index 00000000..35114307 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionSubscriptionsTest.cs @@ -0,0 +1,3921 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; +using Orb.Models.Customers; +using Orb.Models.Subscriptions; +using Plans = Orb.Models.Plans; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionSubscriptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SubscriptionSubscriptions + { + Data = + [ + new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SubscriptionSubscriptions + { + Data = + [ + new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SubscriptionSubscriptions + { + Data = + [ + new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new SubscriptionSubscriptions + { + Data = + [ + new() + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = + [ + new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + ], + Parent = new() + { + ID = "id", + ExternalCustomerID = "external_customer_id", + }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionTest.cs new file mode 100644 index 00000000..1a682c24 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionTest.cs @@ -0,0 +1,4130 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers; +using Orb.Models.Subscriptions; +using Plans = Orb.Models.Plans; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Subscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }; + + string expectedID = "id"; + long expectedActivePlanPhaseOrder = 0; + List expectedAdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAutoCollection = true; + BillingCycleAnchorConfiguration expectedBillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }; + long expectedBillingCycleDay = 1; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedCurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + Customer expectedCustomer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + List expectedDiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedInvoicingThreshold = "invoicing_threshold"; + List expectedMaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + List expectedMinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedName = "name"; + long expectedNetTerms = 0; + SubscriptionChangeMinified expectedPendingSubscriptionChange = new("id"); + Plans::Plan expectedPlan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = Plans::TrialPeriodUnit.Days }, + Version = 0, + }; + List expectedPriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ]; + CouponRedemption expectedRedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = SubscriptionStatus.Active; + SubscriptionTrialInfo expectedTrialInfo = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedActivePlanPhaseOrder, model.ActivePlanPhaseOrder); + Assert.Equal(expectedAdjustmentIntervals.Count, model.AdjustmentIntervals.Count); + for (int i = 0; i < expectedAdjustmentIntervals.Count; i++) + { + Assert.Equal(expectedAdjustmentIntervals[i], model.AdjustmentIntervals[i]); + } + Assert.Equal(expectedAutoCollection, model.AutoCollection); + Assert.Equal( + expectedBillingCycleAnchorConfiguration, + model.BillingCycleAnchorConfiguration + ); + Assert.Equal(expectedBillingCycleDay, model.BillingCycleDay); + Assert.Equal(expectedCreatedAt, model.CreatedAt); + Assert.Equal(expectedCurrentBillingPeriodEndDate, model.CurrentBillingPeriodEndDate); + Assert.Equal(expectedCurrentBillingPeriodStartDate, model.CurrentBillingPeriodStartDate); + Assert.Equal(expectedCustomer, model.Customer); + Assert.Equal(expectedDefaultInvoiceMemo, model.DefaultInvoiceMemo); + Assert.Equal(expectedDiscountIntervals.Count, model.DiscountIntervals.Count); + for (int i = 0; i < expectedDiscountIntervals.Count; i++) + { + Assert.Equal(expectedDiscountIntervals[i], model.DiscountIntervals[i]); + } + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFixedFeeQuantitySchedule.Count, model.FixedFeeQuantitySchedule.Count); + for (int i = 0; i < expectedFixedFeeQuantitySchedule.Count; i++) + { + Assert.Equal(expectedFixedFeeQuantitySchedule[i], model.FixedFeeQuantitySchedule[i]); + } + Assert.Equal(expectedInvoicingThreshold, model.InvoicingThreshold); + Assert.Equal(expectedMaximumIntervals.Count, model.MaximumIntervals.Count); + for (int i = 0; i < expectedMaximumIntervals.Count; i++) + { + Assert.Equal(expectedMaximumIntervals[i], model.MaximumIntervals[i]); + } + Assert.Equal(expectedMetadata.Count, model.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(model.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Metadata[item.Key]); + } + Assert.Equal(expectedMinimumIntervals.Count, model.MinimumIntervals.Count); + for (int i = 0; i < expectedMinimumIntervals.Count; i++) + { + Assert.Equal(expectedMinimumIntervals[i], model.MinimumIntervals[i]); + } + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedNetTerms, model.NetTerms); + Assert.Equal(expectedPendingSubscriptionChange, model.PendingSubscriptionChange); + Assert.Equal(expectedPlan, model.Plan); + Assert.Equal(expectedPriceIntervals.Count, model.PriceIntervals.Count); + for (int i = 0; i < expectedPriceIntervals.Count; i++) + { + Assert.Equal(expectedPriceIntervals[i], model.PriceIntervals[i]); + } + Assert.Equal(expectedRedeemedCoupon, model.RedeemedCoupon); + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedStatus, model.Status); + Assert.Equal(expectedTrialInfo, model.TrialInfo); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Subscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Subscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + long expectedActivePlanPhaseOrder = 0; + List expectedAdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + bool expectedAutoCollection = true; + BillingCycleAnchorConfiguration expectedBillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }; + long expectedBillingCycleDay = 1; + DateTimeOffset expectedCreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedCurrentBillingPeriodEndDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + DateTimeOffset expectedCurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ); + Customer expectedCustomer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + List expectedDiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedInvoicingThreshold = "invoicing_threshold"; + List expectedMaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + List expectedMinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + string expectedName = "name"; + long expectedNetTerms = 0; + SubscriptionChangeMinified expectedPendingSubscriptionChange = new("id"); + Plans::Plan expectedPlan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() { TrialPeriod = 0, TrialPeriodUnit = Plans::TrialPeriodUnit.Days }, + Version = 0, + }; + List expectedPriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ]; + CouponRedemption expectedRedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + ApiEnum expectedStatus = SubscriptionStatus.Active; + SubscriptionTrialInfo expectedTrialInfo = new( + DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") + ); + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedActivePlanPhaseOrder, deserialized.ActivePlanPhaseOrder); + Assert.Equal(expectedAdjustmentIntervals.Count, deserialized.AdjustmentIntervals.Count); + for (int i = 0; i < expectedAdjustmentIntervals.Count; i++) + { + Assert.Equal(expectedAdjustmentIntervals[i], deserialized.AdjustmentIntervals[i]); + } + Assert.Equal(expectedAutoCollection, deserialized.AutoCollection); + Assert.Equal( + expectedBillingCycleAnchorConfiguration, + deserialized.BillingCycleAnchorConfiguration + ); + Assert.Equal(expectedBillingCycleDay, deserialized.BillingCycleDay); + Assert.Equal(expectedCreatedAt, deserialized.CreatedAt); + Assert.Equal(expectedCurrentBillingPeriodEndDate, deserialized.CurrentBillingPeriodEndDate); + Assert.Equal( + expectedCurrentBillingPeriodStartDate, + deserialized.CurrentBillingPeriodStartDate + ); + Assert.Equal(expectedCustomer, deserialized.Customer); + Assert.Equal(expectedDefaultInvoiceMemo, deserialized.DefaultInvoiceMemo); + Assert.Equal(expectedDiscountIntervals.Count, deserialized.DiscountIntervals.Count); + for (int i = 0; i < expectedDiscountIntervals.Count; i++) + { + Assert.Equal(expectedDiscountIntervals[i], deserialized.DiscountIntervals[i]); + } + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal( + expectedFixedFeeQuantitySchedule.Count, + deserialized.FixedFeeQuantitySchedule.Count + ); + for (int i = 0; i < expectedFixedFeeQuantitySchedule.Count; i++) + { + Assert.Equal( + expectedFixedFeeQuantitySchedule[i], + deserialized.FixedFeeQuantitySchedule[i] + ); + } + Assert.Equal(expectedInvoicingThreshold, deserialized.InvoicingThreshold); + Assert.Equal(expectedMaximumIntervals.Count, deserialized.MaximumIntervals.Count); + for (int i = 0; i < expectedMaximumIntervals.Count; i++) + { + Assert.Equal(expectedMaximumIntervals[i], deserialized.MaximumIntervals[i]); + } + Assert.Equal(expectedMetadata.Count, deserialized.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(deserialized.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Metadata[item.Key]); + } + Assert.Equal(expectedMinimumIntervals.Count, deserialized.MinimumIntervals.Count); + for (int i = 0; i < expectedMinimumIntervals.Count; i++) + { + Assert.Equal(expectedMinimumIntervals[i], deserialized.MinimumIntervals[i]); + } + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedNetTerms, deserialized.NetTerms); + Assert.Equal(expectedPendingSubscriptionChange, deserialized.PendingSubscriptionChange); + Assert.Equal(expectedPlan, deserialized.Plan); + Assert.Equal(expectedPriceIntervals.Count, deserialized.PriceIntervals.Count); + for (int i = 0; i < expectedPriceIntervals.Count; i++) + { + Assert.Equal(expectedPriceIntervals[i], deserialized.PriceIntervals[i]); + } + Assert.Equal(expectedRedeemedCoupon, deserialized.RedeemedCoupon); + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedStatus, deserialized.Status); + Assert.Equal(expectedTrialInfo, deserialized.TrialInfo); + } + + [Fact] + public void Validation_Works() + { + var model = new Subscription + { + ID = "id", + ActivePlanPhaseOrder = 0, + AdjustmentIntervals = + [ + new() + { + ID = "id", + Adjustment = new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + AutoCollection = true, + BillingCycleAnchorConfiguration = new() + { + Day = 1, + Month = 1, + Year = 0, + }, + BillingCycleDay = 1, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Customer = new() + { + ID = "id", + AdditionalEmails = ["string"], + AutoCollection = true, + AutoIssuance = true, + Balance = "balance", + BillingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + Email = "email", + EmailDelivery = true, + ExemptFromAutomatedTax = true, + ExternalCustomerID = "external_customer_id", + Hierarchy = new() + { + Children = [new() { ID = "id", ExternalCustomerID = "external_customer_id" }], + Parent = new() { ID = "id", ExternalCustomerID = "external_customer_id" }, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + Name = "name", + PaymentProvider = CustomerPaymentProvider.Quickbooks, + PaymentProviderID = "payment_provider_id", + PortalURL = "portal_url", + ShippingAddress = new() + { + City = "city", + Country = "country", + Line1 = "line1", + Line2 = "line2", + PostalCode = "postal_code", + State = "state", + }, + TaxID = new() + { + Country = Country.Ad, + Type = CustomerTaxIDType.AdNrt, + Value = "value", + }, + Timezone = "timezone", + AccountingSyncConfiguration = new() + { + AccountingProviders = + [ + new() + { + ExternalProviderID = "external_provider_id", + ProviderType = AccountingProviderProviderType.Quickbooks, + }, + ], + Excluded = true, + }, + AutomaticTaxEnabled = true, + PaymentConfiguration = new() + { + PaymentProviders = + [ + new() + { + ProviderType = + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + ExcludedPaymentMethodTypes = ["string"], + }, + ], + }, + ReportingConfiguration = new(true), + }, + DefaultInvoiceMemo = "default_invoice_memo", + DiscountIntervals = + [ + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + FixedFeeQuantitySchedule = + [ + new() + { + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + InvoicingThreshold = "invoicing_threshold", + MaximumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MaximumIntervalFilterField.PriceID, + Operator = MaximumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Metadata = new Dictionary() { { "foo", "string" } }, + MinimumIntervals = + [ + new() + { + AppliesToPriceIntervalIDs = ["string"], + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = MinimumIntervalFilterField.PriceID, + Operator = MinimumIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + Name = "name", + NetTerms = 0, + PendingSubscriptionChange = new("id"), + Plan = new() + { + ID = "id", + Adjustments = + [ + new PlanPhaseUsageDiscountAdjustment() + { + ID = "id", + AdjustmentType = + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + Operator = PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + Values = ["string"], + }, + ], + IsInvoiceLevel = true, + PlanPhaseOrder = 0, + Reason = "reason", + ReplacesAdjustmentID = "replaces_adjustment_id", + UsageDiscount = 0, + }, + ], + BasePlan = new() + { + ID = "m2t5akQeh2obwxeU", + ExternalPlanID = "m2t5akQeh2obwxeU", + Name = "Example plan", + }, + BasePlanID = "base_plan_id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Currency = "currency", + DefaultInvoiceMemo = "default_invoice_memo", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPlanID = "external_plan_id", + InvoicingCurrency = "invoicing_currency", + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + NetTerms = 0, + PlanPhases = + [ + new() + { + ID = "id", + Description = "description", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + Duration = 0, + DurationUnit = Plans::PlanPlanPhaseDurationUnit.Daily, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + Order = 0, + }, + ], + Prices = + [ + new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + ], + Product = new() + { + ID = "id", + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Name = "name", + }, + Status = Plans::PlanStatus.Active, + TrialConfig = new() + { + TrialPeriod = 0, + TrialPeriodUnit = Plans::TrialPeriodUnit.Days, + }, + Version = 0, + }, + PriceIntervals = + [ + new() + { + ID = "id", + BillingCycleDay = 0, + CanDeferBilling = true, + CurrentBillingPeriodEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CurrentBillingPeriodStartDate = DateTimeOffset.Parse( + "2019-12-27T18:11:19.117Z" + ), + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filter = "filter", + FixedFeeQuantityTransitions = + [ + new() + { + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + PriceID = "price_id", + Quantity = 0, + }, + ], + Price = new Unit() + { + ID = "id", + BillableMetric = new("id"), + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + BillingMode = BillingMode.InAdvance, + Cadence = UnitCadence.OneTime, + CompositePriceFilters = + [ + new() + { + Field = CompositePriceFilterField.PriceID, + Operator = CompositePriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + CreatedAt = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + CreditAllocation = new() + { + AllowsRollover = true, + Currency = "currency", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + Filters = + [ + new() + { + Field = Field.PriceID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + }, + Currency = "currency", + Discount = new PercentageDiscount() + { + DiscountType = PercentageDiscountDiscountType.Percentage, + PercentageDiscountValue = 0.15, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = PercentageDiscountFilterField.PriceID, + Operator = PercentageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = DurationUnit.Day, + }, + Item = new() { ID = "id", Name = "name" }, + Maximum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MaximumFilterField.PriceID, + Operator = MaximumFilterOperator.Includes, + Values = ["string"], + }, + ], + MaximumAmount = "maximum_amount", + }, + MaximumAmount = "maximum_amount", + Metadata = new Dictionary() { { "foo", "string" } }, + Minimum = new() + { + AppliesToPriceIDs = ["string"], + Filters = + [ + new() + { + Field = MinimumFilterField.PriceID, + Operator = MinimumFilterOperator.Includes, + Values = ["string"], + }, + ], + MinimumAmount = "minimum_amount", + }, + MinimumAmount = "minimum_amount", + Name = "name", + PlanPhaseOrder = 0, + PriceType = UnitPriceType.UsagePrice, + ReplacesPriceID = "replaces_price_id", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + }, + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageCustomerIDs = ["string"], + }, + ], + RedeemedCoupon = new() + { + CouponID = "coupon_id", + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Status = SubscriptionStatus.Active, + TrialInfo = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")), + }; + + model.Validate(); + } +} + +public class DiscountIntervalTest : TestBase +{ + [Fact] + public void AmountValidationWorks() + { + DiscountInterval value = new( + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + value.Validate(); + } + + [Fact] + public void PercentageValidationWorks() + { + DiscountInterval value = new( + new PercentageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + value.Validate(); + } + + [Fact] + public void UsageValidationWorks() + { + DiscountInterval value = new( + new UsageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + } + ); + value.Validate(); + } + + [Fact] + public void AmountSerializationRoundtripWorks() + { + DiscountInterval value = new( + new AmountDiscountInterval() + { + AmountDiscount = "amount_discount", + AppliesToPriceIntervalIDs = ["string"], + DiscountType = AmountDiscountIntervalDiscountType.Amount, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = AmountDiscountIntervalFilterField.PriceID, + Operator = AmountDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void PercentageSerializationRoundtripWorks() + { + DiscountInterval value = new( + new PercentageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = PercentageDiscountIntervalDiscountType.Percentage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = PercentageDiscountIntervalFilterField.PriceID, + Operator = PercentageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + PercentageDiscount = 0.15, + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UsageSerializationRoundtripWorks() + { + DiscountInterval value = new( + new UsageDiscountInterval() + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class SubscriptionStatusTest : TestBase +{ + [Theory] + [InlineData(SubscriptionStatus.Active)] + [InlineData(SubscriptionStatus.Ended)] + [InlineData(SubscriptionStatus.Upcoming)] + public void Validation_Works(SubscriptionStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SubscriptionStatus.Active)] + [InlineData(SubscriptionStatus.Ended)] + [InlineData(SubscriptionStatus.Upcoming)] + public void SerializationRoundtrip_Works(SubscriptionStatus rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionTriggerPhaseParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionTriggerPhaseParamsTest.cs new file mode 100644 index 00000000..f7985c2e --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionTriggerPhaseParamsTest.cs @@ -0,0 +1,53 @@ +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionTriggerPhaseParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionTriggerPhaseParams + { + SubscriptionID = "subscription_id", + AllowInvoiceCreditOrVoid = true, + EffectiveDate = "2019-12-27", + }; + + string expectedSubscriptionID = "subscription_id"; + bool expectedAllowInvoiceCreditOrVoid = true; + string expectedEffectiveDate = "2019-12-27"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedAllowInvoiceCreditOrVoid, parameters.AllowInvoiceCreditOrVoid); + Assert.Equal(expectedEffectiveDate, parameters.EffectiveDate); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionTriggerPhaseParams { SubscriptionID = "subscription_id" }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.EffectiveDate); + Assert.False(parameters.RawBodyData.ContainsKey("effective_date")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionTriggerPhaseParams + { + SubscriptionID = "subscription_id", + + AllowInvoiceCreditOrVoid = null, + EffectiveDate = null, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.EffectiveDate); + Assert.False(parameters.RawBodyData.ContainsKey("effective_date")); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUnscheduleCancellationParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUnscheduleCancellationParamsTest.cs new file mode 100644 index 00000000..b9ab7ab5 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUnscheduleCancellationParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUnscheduleCancellationParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionUnscheduleCancellationParams + { + SubscriptionID = "subscription_id", + }; + + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParamsTest.cs new file mode 100644 index 00000000..fb27a48a --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParamsTest.cs @@ -0,0 +1,22 @@ +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUnscheduleFixedFeeQuantityUpdatesParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionUnscheduleFixedFeeQuantityUpdatesParams + { + SubscriptionID = "subscription_id", + PriceID = "price_id", + }; + + string expectedSubscriptionID = "subscription_id"; + string expectedPriceID = "price_id"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedPriceID, parameters.PriceID); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParamsTest.cs new file mode 100644 index 00000000..0b030919 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParamsTest.cs @@ -0,0 +1,19 @@ +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUnschedulePendingPlanChangesParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionUnschedulePendingPlanChangesParams + { + SubscriptionID = "subscription_id", + }; + + string expectedSubscriptionID = "subscription_id"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParamsTest.cs new file mode 100644 index 00000000..cd91cc5d --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParamsTest.cs @@ -0,0 +1,174 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUpdateFixedFeeQuantityParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionUpdateFixedFeeQuantityParams + { + SubscriptionID = "subscription_id", + PriceID = "price_id", + Quantity = 0, + AllowInvoiceCreditOrVoid = true, + ChangeOption = SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate, + EffectiveDate = "2022-12-21", + }; + + string expectedSubscriptionID = "subscription_id"; + string expectedPriceID = "price_id"; + double expectedQuantity = 0; + bool expectedAllowInvoiceCreditOrVoid = true; + ApiEnum expectedChangeOption = + SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate; + string expectedEffectiveDate = "2022-12-21"; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedPriceID, parameters.PriceID); + Assert.Equal(expectedQuantity, parameters.Quantity); + Assert.Equal(expectedAllowInvoiceCreditOrVoid, parameters.AllowInvoiceCreditOrVoid); + Assert.Equal(expectedChangeOption, parameters.ChangeOption); + Assert.Equal(expectedEffectiveDate, parameters.EffectiveDate); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionUpdateFixedFeeQuantityParams + { + SubscriptionID = "subscription_id", + PriceID = "price_id", + Quantity = 0, + AllowInvoiceCreditOrVoid = true, + EffectiveDate = "2022-12-21", + }; + + Assert.Null(parameters.ChangeOption); + Assert.False(parameters.RawBodyData.ContainsKey("change_option")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new SubscriptionUpdateFixedFeeQuantityParams + { + SubscriptionID = "subscription_id", + PriceID = "price_id", + Quantity = 0, + AllowInvoiceCreditOrVoid = true, + EffectiveDate = "2022-12-21", + + // Null should be interpreted as omitted for these properties + ChangeOption = null, + }; + + Assert.Null(parameters.ChangeOption); + Assert.False(parameters.RawBodyData.ContainsKey("change_option")); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionUpdateFixedFeeQuantityParams + { + SubscriptionID = "subscription_id", + PriceID = "price_id", + Quantity = 0, + ChangeOption = SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.EffectiveDate); + Assert.False(parameters.RawBodyData.ContainsKey("effective_date")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionUpdateFixedFeeQuantityParams + { + SubscriptionID = "subscription_id", + PriceID = "price_id", + Quantity = 0, + ChangeOption = SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate, + + AllowInvoiceCreditOrVoid = null, + EffectiveDate = null, + }; + + Assert.Null(parameters.AllowInvoiceCreditOrVoid); + Assert.False(parameters.RawBodyData.ContainsKey("allow_invoice_credit_or_void")); + Assert.Null(parameters.EffectiveDate); + Assert.False(parameters.RawBodyData.ContainsKey("effective_date")); + } +} + +public class SubscriptionUpdateFixedFeeQuantityParamsChangeOptionTest : TestBase +{ + [Theory] + [InlineData(SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate)] + [InlineData(SubscriptionUpdateFixedFeeQuantityParamsChangeOption.UpcomingInvoice)] + [InlineData(SubscriptionUpdateFixedFeeQuantityParamsChangeOption.EffectiveDate)] + public void Validation_Works(SubscriptionUpdateFixedFeeQuantityParamsChangeOption rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate)] + [InlineData(SubscriptionUpdateFixedFeeQuantityParamsChangeOption.UpcomingInvoice)] + [InlineData(SubscriptionUpdateFixedFeeQuantityParamsChangeOption.EffectiveDate)] + public void SerializationRoundtrip_Works( + SubscriptionUpdateFixedFeeQuantityParamsChangeOption rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateParamsTest.cs new file mode 100644 index 00000000..97dea919 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateParamsTest.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUpdateParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionUpdateParams + { + SubscriptionID = "subscription_id", + AutoCollection = true, + DefaultInvoiceMemo = "default_invoice_memo", + InvoicingThreshold = "10.00", + Metadata = new Dictionary() { { "foo", "string" } }, + NetTerms = 0, + }; + + string expectedSubscriptionID = "subscription_id"; + bool expectedAutoCollection = true; + string expectedDefaultInvoiceMemo = "default_invoice_memo"; + string expectedInvoicingThreshold = "10.00"; + Dictionary expectedMetadata = new() { { "foo", "string" } }; + long expectedNetTerms = 0; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedAutoCollection, parameters.AutoCollection); + Assert.Equal(expectedDefaultInvoiceMemo, parameters.DefaultInvoiceMemo); + Assert.Equal(expectedInvoicingThreshold, parameters.InvoicingThreshold); + Assert.NotNull(parameters.Metadata); + Assert.Equal(expectedMetadata.Count, parameters.Metadata.Count); + foreach (var item in expectedMetadata) + { + Assert.True(parameters.Metadata.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, parameters.Metadata[item.Key]); + } + Assert.Equal(expectedNetTerms, parameters.NetTerms); + } + + [Fact] + public void OptionalNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionUpdateParams { SubscriptionID = "subscription_id" }; + + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.InvoicingThreshold); + Assert.False(parameters.RawBodyData.ContainsKey("invoicing_threshold")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + } + + [Fact] + public void OptionalNullableParamsSetToNullAreSetToNull_Works() + { + var parameters = new SubscriptionUpdateParams + { + SubscriptionID = "subscription_id", + + AutoCollection = null, + DefaultInvoiceMemo = null, + InvoicingThreshold = null, + Metadata = null, + NetTerms = null, + }; + + Assert.Null(parameters.AutoCollection); + Assert.False(parameters.RawBodyData.ContainsKey("auto_collection")); + Assert.Null(parameters.DefaultInvoiceMemo); + Assert.False(parameters.RawBodyData.ContainsKey("default_invoice_memo")); + Assert.Null(parameters.InvoicingThreshold); + Assert.False(parameters.RawBodyData.ContainsKey("invoicing_threshold")); + Assert.Null(parameters.Metadata); + Assert.False(parameters.RawBodyData.ContainsKey("metadata")); + Assert.Null(parameters.NetTerms); + Assert.False(parameters.RawBodyData.ContainsKey("net_terms")); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateTrialParamsTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateTrialParamsTest.cs new file mode 100644 index 00000000..c6e7526d --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUpdateTrialParamsTest.cs @@ -0,0 +1,151 @@ +using System; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUpdateTrialParamsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var parameters = new SubscriptionUpdateTrialParams + { + SubscriptionID = "subscription_id", + TrialEndDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"), + Shift = true, + }; + + string expectedSubscriptionID = "subscription_id"; + TrialEndDate expectedTrialEndDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"); + bool expectedShift = true; + + Assert.Equal(expectedSubscriptionID, parameters.SubscriptionID); + Assert.Equal(expectedTrialEndDate, parameters.TrialEndDate); + Assert.Equal(expectedShift, parameters.Shift); + } + + [Fact] + public void OptionalNonNullableParamsUnsetAreNotSet_Works() + { + var parameters = new SubscriptionUpdateTrialParams + { + SubscriptionID = "subscription_id", + TrialEndDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"), + }; + + Assert.Null(parameters.Shift); + Assert.False(parameters.RawBodyData.ContainsKey("shift")); + } + + [Fact] + public void OptionalNonNullableParamsSetToNullAreNotSet_Works() + { + var parameters = new SubscriptionUpdateTrialParams + { + SubscriptionID = "subscription_id", + TrialEndDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z"), + + // Null should be interpreted as omitted for these properties + Shift = null, + }; + + Assert.Null(parameters.Shift); + Assert.False(parameters.RawBodyData.ContainsKey("shift")); + } +} + +public class TrialEndDateTest : TestBase +{ + [Fact] + public void DateTimeOffsetValidationWorks() + { + TrialEndDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + value.Validate(); + } + + [Fact] + public void UnionMember1ValidationWorks() + { + TrialEndDate value = new(UnionMember1.Immediate); + value.Validate(); + } + + [Fact] + public void DateTimeOffsetSerializationRoundtripWorks() + { + TrialEndDate value = new(DateTimeOffset.Parse("2019-12-27T18:11:19.117Z")); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void UnionMember1SerializationRoundtripWorks() + { + TrialEndDate value = new(UnionMember1.Immediate); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class UnionMember1Test : TestBase +{ + [Theory] + [InlineData(UnionMember1.Immediate)] + public void Validation_Works(UnionMember1 rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UnionMember1.Immediate)] + public void SerializationRoundtrip_Works(UnionMember1 rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/Subscriptions/SubscriptionUsageTest.cs b/src/Orb.Tests/Models/Subscriptions/SubscriptionUsageTest.cs new file mode 100644 index 00000000..ea4d3bd5 --- /dev/null +++ b/src/Orb.Tests/Models/Subscriptions/SubscriptionUsageTest.cs @@ -0,0 +1,1364 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Models.Subscriptions; + +public class SubscriptionUsageTest : TestBase +{ + [Fact] + public void UngroupedValidationWorks() + { + SubscriptionUsage value = new( + new UngroupedSubscriptionUsage( + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ] + ) + ); + value.Validate(); + } + + [Fact] + public void GroupedValidationWorks() + { + SubscriptionUsage value = new( + new GroupedSubscriptionUsage() + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + } + ); + value.Validate(); + } + + [Fact] + public void UngroupedSerializationRoundtripWorks() + { + SubscriptionUsage value = new( + new UngroupedSubscriptionUsage( + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ] + ) + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GroupedSerializationRoundtripWorks() + { + SubscriptionUsage value = new( + new GroupedSubscriptionUsage() + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + } + ); + string element = JsonSerializer.Serialize(value); + var deserialized = JsonSerializer.Deserialize(element); + + Assert.Equal(value, deserialized); + } +} + +public class UngroupedSubscriptionUsageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UngroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ], + }; + + List expectedData = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ]; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UngroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UngroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ]; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new UngroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }, + ], + }; + + model.Validate(); + } +} + +public class DataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Data + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }; + + BillableMetric expectedBillableMetric = new() { ID = "id", Name = "name" }; + List expectedUsage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + ApiEnum expectedViewMode = DataViewMode.Periodic; + + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedUsage.Count, model.Usage.Count); + for (int i = 0; i < expectedUsage.Count; i++) + { + Assert.Equal(expectedUsage[i], model.Usage[i]); + } + Assert.Equal(expectedViewMode, model.ViewMode); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Data + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Data + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + BillableMetric expectedBillableMetric = new() { ID = "id", Name = "name" }; + List expectedUsage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + ApiEnum expectedViewMode = DataViewMode.Periodic; + + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedUsage.Count, deserialized.Usage.Count); + for (int i = 0; i < expectedUsage.Count; i++) + { + Assert.Equal(expectedUsage[i], deserialized.Usage[i]); + } + Assert.Equal(expectedViewMode, deserialized.ViewMode); + } + + [Fact] + public void Validation_Works() + { + var model = new Data + { + BillableMetric = new() { ID = "id", Name = "name" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = DataViewMode.Periodic, + }; + + model.Validate(); + } +} + +public class BillableMetricTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new BillableMetric { ID = "id", Name = "name" }; + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new BillableMetric { ID = "id", Name = "name" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new BillableMetric { ID = "id", Name = "name" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new BillableMetric { ID = "id", Name = "name" }; + + model.Validate(); + } +} + +public class DataUsageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new DataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + double expectedQuantity = 0; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new DataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new DataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedQuantity = 0; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + } + + [Fact] + public void Validation_Works() + { + var model = new DataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class DataViewModeTest : TestBase +{ + [Theory] + [InlineData(DataViewMode.Periodic)] + [InlineData(DataViewMode.Cumulative)] + public void Validation_Works(DataViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(DataViewMode.Periodic)] + [InlineData(DataViewMode.Cumulative)] + public void SerializationRoundtrip_Works(DataViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class GroupedSubscriptionUsageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + List expectedData = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, model.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], model.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, model.PaginationMetadata); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedData = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ]; + PaginationMetadata expectedPaginationMetadata = new() + { + HasMore = true, + NextCursor = "next_cursor", + }; + + Assert.Equal(expectedData.Count, deserialized.Data.Count); + for (int i = 0; i < expectedData.Count; i++) + { + Assert.Equal(expectedData[i], deserialized.Data[i]); + } + Assert.Equal(expectedPaginationMetadata, deserialized.PaginationMetadata); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + PaginationMetadata = new() { HasMore = true, NextCursor = "next_cursor" }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + }; + + Assert.Null(model.PaginationMetadata); + Assert.False(model.RawData.ContainsKey("pagination_metadata")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + + PaginationMetadata = null, + }; + + Assert.Null(model.PaginationMetadata); + Assert.True(model.RawData.ContainsKey("pagination_metadata")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new GroupedSubscriptionUsage + { + Data = + [ + new() + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }, + ], + + PaginationMetadata = null, + }; + + model.Validate(); + } +} + +public class GroupedSubscriptionUsageDataTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedSubscriptionUsageData + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() { PropertyKey = "property_key", PropertyValue = "property_value" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }; + + GroupedSubscriptionUsageDataBillableMetric expectedBillableMetric = new() + { + ID = "id", + Name = "name", + }; + MetricGroup expectedMetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }; + List expectedUsage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + ApiEnum expectedViewMode = + GroupedSubscriptionUsageDataViewMode.Periodic; + + Assert.Equal(expectedBillableMetric, model.BillableMetric); + Assert.Equal(expectedMetricGroup, model.MetricGroup); + Assert.Equal(expectedUsage.Count, model.Usage.Count); + for (int i = 0; i < expectedUsage.Count; i++) + { + Assert.Equal(expectedUsage[i], model.Usage[i]); + } + Assert.Equal(expectedViewMode, model.ViewMode); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedSubscriptionUsageData + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() { PropertyKey = "property_key", PropertyValue = "property_value" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedSubscriptionUsageData + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() { PropertyKey = "property_key", PropertyValue = "property_value" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + GroupedSubscriptionUsageDataBillableMetric expectedBillableMetric = new() + { + ID = "id", + Name = "name", + }; + MetricGroup expectedMetricGroup = new() + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }; + List expectedUsage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ]; + ApiEnum expectedViewMode = + GroupedSubscriptionUsageDataViewMode.Periodic; + + Assert.Equal(expectedBillableMetric, deserialized.BillableMetric); + Assert.Equal(expectedMetricGroup, deserialized.MetricGroup); + Assert.Equal(expectedUsage.Count, deserialized.Usage.Count); + for (int i = 0; i < expectedUsage.Count; i++) + { + Assert.Equal(expectedUsage[i], deserialized.Usage[i]); + } + Assert.Equal(expectedViewMode, deserialized.ViewMode); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedSubscriptionUsageData + { + BillableMetric = new() { ID = "id", Name = "name" }, + MetricGroup = new() { PropertyKey = "property_key", PropertyValue = "property_value" }, + Usage = + [ + new() + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + ], + ViewMode = GroupedSubscriptionUsageDataViewMode.Periodic, + }; + + model.Validate(); + } +} + +public class GroupedSubscriptionUsageDataBillableMetricTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedSubscriptionUsageDataBillableMetric { ID = "id", Name = "name" }; + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, model.ID); + Assert.Equal(expectedName, model.Name); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedSubscriptionUsageDataBillableMetric { ID = "id", Name = "name" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + json + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedSubscriptionUsageDataBillableMetric { ID = "id", Name = "name" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize( + element + ); + Assert.NotNull(deserialized); + + string expectedID = "id"; + string expectedName = "name"; + + Assert.Equal(expectedID, deserialized.ID); + Assert.Equal(expectedName, deserialized.Name); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedSubscriptionUsageDataBillableMetric { ID = "id", Name = "name" }; + + model.Validate(); + } +} + +public class MetricGroupTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new MetricGroup + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }; + + string expectedPropertyKey = "property_key"; + string expectedPropertyValue = "property_value"; + + Assert.Equal(expectedPropertyKey, model.PropertyKey); + Assert.Equal(expectedPropertyValue, model.PropertyValue); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new MetricGroup + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new MetricGroup + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedPropertyKey = "property_key"; + string expectedPropertyValue = "property_value"; + + Assert.Equal(expectedPropertyKey, deserialized.PropertyKey); + Assert.Equal(expectedPropertyValue, deserialized.PropertyValue); + } + + [Fact] + public void Validation_Works() + { + var model = new MetricGroup + { + PropertyKey = "property_key", + PropertyValue = "property_value", + }; + + model.Validate(); + } +} + +public class GroupedSubscriptionUsageDataUsageTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new GroupedSubscriptionUsageDataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + double expectedQuantity = 0; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedTimeframeEnd, model.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, model.TimeframeStart); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new GroupedSubscriptionUsageDataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new GroupedSubscriptionUsageDataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedQuantity = 0; + DateTimeOffset expectedTimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + DateTimeOffset expectedTimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedTimeframeEnd, deserialized.TimeframeEnd); + Assert.Equal(expectedTimeframeStart, deserialized.TimeframeStart); + } + + [Fact] + public void Validation_Works() + { + var model = new GroupedSubscriptionUsageDataUsage + { + Quantity = 0, + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }; + + model.Validate(); + } +} + +public class GroupedSubscriptionUsageDataViewModeTest : TestBase +{ + [Theory] + [InlineData(GroupedSubscriptionUsageDataViewMode.Periodic)] + [InlineData(GroupedSubscriptionUsageDataViewMode.Cumulative)] + public void Validation_Works(GroupedSubscriptionUsageDataViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(GroupedSubscriptionUsageDataViewMode.Periodic)] + [InlineData(GroupedSubscriptionUsageDataViewMode.Cumulative)] + public void SerializationRoundtrip_Works(GroupedSubscriptionUsageDataViewMode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/TaxAmountTest.cs b/src/Orb.Tests/Models/TaxAmountTest.cs new file mode 100644 index 00000000..a86dfdd4 --- /dev/null +++ b/src/Orb.Tests/Models/TaxAmountTest.cs @@ -0,0 +1,78 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class TaxAmountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TaxAmount + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }; + + string expectedAmount = "amount"; + string expectedTaxRateDescription = "tax_rate_description"; + string expectedTaxRatePercentage = "tax_rate_percentage"; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedTaxRateDescription, model.TaxRateDescription); + Assert.Equal(expectedTaxRatePercentage, model.TaxRatePercentage); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TaxAmount + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TaxAmount + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "amount"; + string expectedTaxRateDescription = "tax_rate_description"; + string expectedTaxRatePercentage = "tax_rate_percentage"; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedTaxRateDescription, deserialized.TaxRateDescription); + Assert.Equal(expectedTaxRatePercentage, deserialized.TaxRatePercentage); + } + + [Fact] + public void Validation_Works() + { + var model = new TaxAmount + { + Amount = "amount", + TaxRateDescription = "tax_rate_description", + TaxRatePercentage = "tax_rate_percentage", + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/TierSubLineItemTest.cs b/src/Orb.Tests/Models/TierSubLineItemTest.cs new file mode 100644 index 00000000..8e6f54c3 --- /dev/null +++ b/src/Orb.Tests/Models/TierSubLineItemTest.cs @@ -0,0 +1,264 @@ +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class TierSubLineItemTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TierSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + }; + + string expectedAmount = "9.00"; + SubLineItemGrouping expectedGrouping = new() { Key = "region", Value = "west" }; + string expectedName = "Tier One"; + double expectedQuantity = 5; + TierConfig expectedTierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }; + ApiEnum expectedType = TierSubLineItemType.Tier; + + Assert.Equal(expectedAmount, model.Amount); + Assert.Equal(expectedGrouping, model.Grouping); + Assert.Equal(expectedName, model.Name); + Assert.Equal(expectedQuantity, model.Quantity); + Assert.Equal(expectedTierConfig, model.TierConfig); + Assert.Equal(expectedType, model.Type); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TierSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TierSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedAmount = "9.00"; + SubLineItemGrouping expectedGrouping = new() { Key = "region", Value = "west" }; + string expectedName = "Tier One"; + double expectedQuantity = 5; + TierConfig expectedTierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }; + ApiEnum expectedType = TierSubLineItemType.Tier; + + Assert.Equal(expectedAmount, deserialized.Amount); + Assert.Equal(expectedGrouping, deserialized.Grouping); + Assert.Equal(expectedName, deserialized.Name); + Assert.Equal(expectedQuantity, deserialized.Quantity); + Assert.Equal(expectedTierConfig, deserialized.TierConfig); + Assert.Equal(expectedType, deserialized.Type); + } + + [Fact] + public void Validation_Works() + { + var model = new TierSubLineItem + { + Amount = "9.00", + Grouping = new() { Key = "region", Value = "west" }, + Name = "Tier One", + Quantity = 5, + TierConfig = new() + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }, + Type = TierSubLineItemType.Tier, + }; + + model.Validate(); + } +} + +public class TierConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TierConfig + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }; + + double expectedFirstUnit = 1; + double expectedLastUnit = 1000; + string expectedUnitAmount = "3.00"; + + Assert.Equal(expectedFirstUnit, model.FirstUnit); + Assert.Equal(expectedLastUnit, model.LastUnit); + Assert.Equal(expectedUnitAmount, model.UnitAmount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TierConfig + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TierConfig + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + double expectedFirstUnit = 1; + double expectedLastUnit = 1000; + string expectedUnitAmount = "3.00"; + + Assert.Equal(expectedFirstUnit, deserialized.FirstUnit); + Assert.Equal(expectedLastUnit, deserialized.LastUnit); + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + } + + [Fact] + public void Validation_Works() + { + var model = new TierConfig + { + FirstUnit = 1, + LastUnit = 1000, + UnitAmount = "3.00", + }; + + model.Validate(); + } +} + +public class TierSubLineItemTypeTest : TestBase +{ + [Theory] + [InlineData(TierSubLineItemType.Tier)] + public void Validation_Works(TierSubLineItemType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TierSubLineItemType.Tier)] + public void SerializationRoundtrip_Works(TierSubLineItemType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/TieredConfigTest.cs b/src/Orb.Tests/Models/TieredConfigTest.cs new file mode 100644 index 00000000..13c36e90 --- /dev/null +++ b/src/Orb.Tests/Models/TieredConfigTest.cs @@ -0,0 +1,211 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class TieredConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + + List expectedTiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ]; + bool expectedProrated = true; + + Assert.Equal(expectedTiers.Count, model.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], model.Tiers[i]); + } + Assert.Equal(expectedProrated, model.Prorated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedTiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ]; + bool expectedProrated = true; + + Assert.Equal(expectedTiers.Count, deserialized.Tiers.Count); + for (int i = 0; i < expectedTiers.Count; i++) + { + Assert.Equal(expectedTiers[i], deserialized.Tiers[i]); + } + Assert.Equal(expectedProrated, deserialized.Prorated); + } + + [Fact] + public void Validation_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + Prorated = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new TieredConfig + { + Tiers = + [ + new() + { + FirstUnit = 0, + UnitAmount = "unit_amount", + LastUnit = 0, + }, + ], + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/TopLevel/TopLevelPingParamsTest.cs b/src/Orb.Tests/Models/TopLevel/TopLevelPingParamsTest.cs new file mode 100644 index 00000000..4091025e --- /dev/null +++ b/src/Orb.Tests/Models/TopLevel/TopLevelPingParamsTest.cs @@ -0,0 +1 @@ +namespace Orb.Tests.Models.TopLevel; diff --git a/src/Orb.Tests/Models/TopLevel/TopLevelPingResponseTest.cs b/src/Orb.Tests/Models/TopLevel/TopLevelPingResponseTest.cs new file mode 100644 index 00000000..1456a9d1 --- /dev/null +++ b/src/Orb.Tests/Models/TopLevel/TopLevelPingResponseTest.cs @@ -0,0 +1,50 @@ +using System.Text.Json; +using Orb.Models.TopLevel; + +namespace Orb.Tests.Models.TopLevel; + +public class TopLevelPingResponseTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TopLevelPingResponse { Response = "response" }; + + string expectedResponse = "response"; + + Assert.Equal(expectedResponse, model.Response); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TopLevelPingResponse { Response = "response" }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TopLevelPingResponse { Response = "response" }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedResponse = "response"; + + Assert.Equal(expectedResponse, deserialized.Response); + } + + [Fact] + public void Validation_Works() + { + var model = new TopLevelPingResponse { Response = "response" }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/TrialDiscountTest.cs b/src/Orb.Tests/Models/TrialDiscountTest.cs new file mode 100644 index 00000000..911057cf --- /dev/null +++ b/src/Orb.Tests/Models/TrialDiscountTest.cs @@ -0,0 +1,505 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class TrialDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TrialDiscount + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + }; + + ApiEnum expectedDiscountType = + TrialDiscountDiscountType.Trial; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + string expectedTrialAmountDiscount = "trial_amount_discount"; + double expectedTrialPercentageDiscount = 0; + + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedReason, model.Reason); + Assert.Equal(expectedTrialAmountDiscount, model.TrialAmountDiscount); + Assert.Equal(expectedTrialPercentageDiscount, model.TrialPercentageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TrialDiscount + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TrialDiscount + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedDiscountType = + TrialDiscountDiscountType.Trial; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + string expectedTrialAmountDiscount = "trial_amount_discount"; + double expectedTrialPercentageDiscount = 0; + + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedReason, deserialized.Reason); + Assert.Equal(expectedTrialAmountDiscount, deserialized.TrialAmountDiscount); + Assert.Equal(expectedTrialPercentageDiscount, deserialized.TrialPercentageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new TrialDiscount + { + DiscountType = TrialDiscountDiscountType.Trial, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + TrialAmountDiscount = "trial_amount_discount", + TrialPercentageDiscount = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new TrialDiscount { DiscountType = TrialDiscountDiscountType.Trial }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + Assert.Null(model.TrialAmountDiscount); + Assert.False(model.RawData.ContainsKey("trial_amount_discount")); + Assert.Null(model.TrialPercentageDiscount); + Assert.False(model.RawData.ContainsKey("trial_percentage_discount")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new TrialDiscount { DiscountType = TrialDiscountDiscountType.Trial }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new TrialDiscount + { + DiscountType = TrialDiscountDiscountType.Trial, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + TrialAmountDiscount = null, + TrialPercentageDiscount = null, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + Assert.Null(model.TrialAmountDiscount); + Assert.True(model.RawData.ContainsKey("trial_amount_discount")); + Assert.Null(model.TrialPercentageDiscount); + Assert.True(model.RawData.ContainsKey("trial_percentage_discount")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new TrialDiscount + { + DiscountType = TrialDiscountDiscountType.Trial, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + TrialAmountDiscount = null, + TrialPercentageDiscount = null, + }; + + model.Validate(); + } +} + +public class TrialDiscountDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(TrialDiscountDiscountType.Trial)] + public void Validation_Works(TrialDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TrialDiscountDiscountType.Trial)] + public void SerializationRoundtrip_Works(TrialDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TrialDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new TrialDiscountFilter + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = TrialDiscountFilterField.PriceID; + ApiEnum expectedOperator = + TrialDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new TrialDiscountFilter + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new TrialDiscountFilter + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = TrialDiscountFilterField.PriceID; + ApiEnum expectedOperator = + TrialDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new TrialDiscountFilter + { + Field = TrialDiscountFilterField.PriceID, + Operator = TrialDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class TrialDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(TrialDiscountFilterField.PriceID)] + [InlineData(TrialDiscountFilterField.ItemID)] + [InlineData(TrialDiscountFilterField.PriceType)] + [InlineData(TrialDiscountFilterField.Currency)] + [InlineData(TrialDiscountFilterField.PricingUnitID)] + public void Validation_Works(TrialDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TrialDiscountFilterField.PriceID)] + [InlineData(TrialDiscountFilterField.ItemID)] + [InlineData(TrialDiscountFilterField.PriceType)] + [InlineData(TrialDiscountFilterField.Currency)] + [InlineData(TrialDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(TrialDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class TrialDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(TrialDiscountFilterOperator.Includes)] + [InlineData(TrialDiscountFilterOperator.Excludes)] + public void Validation_Works(TrialDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(TrialDiscountFilterOperator.Includes)] + [InlineData(TrialDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(TrialDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/UnitConfigTest.cs b/src/Orb.Tests/Models/UnitConfigTest.cs new file mode 100644 index 00000000..e5a61268 --- /dev/null +++ b/src/Orb.Tests/Models/UnitConfigTest.cs @@ -0,0 +1,100 @@ +using System.Text.Json; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class UnitConfigTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UnitConfig { UnitAmount = "unit_amount", Prorated = true }; + + string expectedUnitAmount = "unit_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedUnitAmount, model.UnitAmount); + Assert.Equal(expectedProrated, model.Prorated); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UnitConfig { UnitAmount = "unit_amount", Prorated = true }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UnitConfig { UnitAmount = "unit_amount", Prorated = true }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + string expectedUnitAmount = "unit_amount"; + bool expectedProrated = true; + + Assert.Equal(expectedUnitAmount, deserialized.UnitAmount); + Assert.Equal(expectedProrated, deserialized.Prorated); + } + + [Fact] + public void Validation_Works() + { + var model = new UnitConfig { UnitAmount = "unit_amount", Prorated = true }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new UnitConfig { UnitAmount = "unit_amount" }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new UnitConfig { UnitAmount = "unit_amount" }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new UnitConfig + { + UnitAmount = "unit_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + Assert.Null(model.Prorated); + Assert.False(model.RawData.ContainsKey("prorated")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new UnitConfig + { + UnitAmount = "unit_amount", + + // Null should be interpreted as omitted for these properties + Prorated = null, + }; + + model.Validate(); + } +} diff --git a/src/Orb.Tests/Models/UsageDiscountIntervalTest.cs b/src/Orb.Tests/Models/UsageDiscountIntervalTest.cs new file mode 100644 index 00000000..46aeb33a --- /dev/null +++ b/src/Orb.Tests/Models/UsageDiscountIntervalTest.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class UsageDiscountIntervalTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UsageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + }; + + List expectedAppliesToPriceIntervalIDs = ["string"]; + ApiEnum expectedDiscountType = + UsageDiscountIntervalDiscountType.Usage; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + double expectedUsageDiscount = 0; + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + model.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIntervalIDs[i], model.AppliesToPriceIntervalIDs[i]); + } + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedEndDate, model.EndDate); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedStartDate, model.StartDate); + Assert.Equal(expectedUsageDiscount, model.UsageDiscount); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UsageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UsageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + List expectedAppliesToPriceIntervalIDs = ["string"]; + ApiEnum expectedDiscountType = + UsageDiscountIntervalDiscountType.Usage; + DateTimeOffset expectedEndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + List expectedFilters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ]; + DateTimeOffset expectedStartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"); + double expectedUsageDiscount = 0; + + Assert.Equal( + expectedAppliesToPriceIntervalIDs.Count, + deserialized.AppliesToPriceIntervalIDs.Count + ); + for (int i = 0; i < expectedAppliesToPriceIntervalIDs.Count; i++) + { + Assert.Equal( + expectedAppliesToPriceIntervalIDs[i], + deserialized.AppliesToPriceIntervalIDs[i] + ); + } + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedEndDate, deserialized.EndDate); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedStartDate, deserialized.StartDate); + Assert.Equal(expectedUsageDiscount, deserialized.UsageDiscount); + } + + [Fact] + public void Validation_Works() + { + var model = new UsageDiscountInterval + { + AppliesToPriceIntervalIDs = ["string"], + DiscountType = UsageDiscountIntervalDiscountType.Usage, + EndDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }, + ], + StartDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + UsageDiscount = 0, + }; + + model.Validate(); + } +} + +public class UsageDiscountIntervalDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(UsageDiscountIntervalDiscountType.Usage)] + public void Validation_Works(UsageDiscountIntervalDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UsageDiscountIntervalDiscountType.Usage)] + public void SerializationRoundtrip_Works(UsageDiscountIntervalDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UsageDiscountIntervalFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UsageDiscountIntervalFilter + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = + UsageDiscountIntervalFilterField.PriceID; + ApiEnum expectedOperator = + UsageDiscountIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UsageDiscountIntervalFilter + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UsageDiscountIntervalFilter + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = + UsageDiscountIntervalFilterField.PriceID; + ApiEnum expectedOperator = + UsageDiscountIntervalFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new UsageDiscountIntervalFilter + { + Field = UsageDiscountIntervalFilterField.PriceID, + Operator = UsageDiscountIntervalFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class UsageDiscountIntervalFilterFieldTest : TestBase +{ + [Theory] + [InlineData(UsageDiscountIntervalFilterField.PriceID)] + [InlineData(UsageDiscountIntervalFilterField.ItemID)] + [InlineData(UsageDiscountIntervalFilterField.PriceType)] + [InlineData(UsageDiscountIntervalFilterField.Currency)] + [InlineData(UsageDiscountIntervalFilterField.PricingUnitID)] + public void Validation_Works(UsageDiscountIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UsageDiscountIntervalFilterField.PriceID)] + [InlineData(UsageDiscountIntervalFilterField.ItemID)] + [InlineData(UsageDiscountIntervalFilterField.PriceType)] + [InlineData(UsageDiscountIntervalFilterField.Currency)] + [InlineData(UsageDiscountIntervalFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(UsageDiscountIntervalFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class UsageDiscountIntervalFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(UsageDiscountIntervalFilterOperator.Includes)] + [InlineData(UsageDiscountIntervalFilterOperator.Excludes)] + public void Validation_Works(UsageDiscountIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UsageDiscountIntervalFilterOperator.Includes)] + [InlineData(UsageDiscountIntervalFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(UsageDiscountIntervalFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Models/UsageDiscountTest.cs b/src/Orb.Tests/Models/UsageDiscountTest.cs new file mode 100644 index 00000000..920ddaba --- /dev/null +++ b/src/Orb.Tests/Models/UsageDiscountTest.cs @@ -0,0 +1,495 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; + +namespace Orb.Tests.Models; + +public class UsageDiscountTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + ApiEnum expectedDiscountType = + UsageDiscountDiscountType.Usage; + double expectedUsageDiscountValue = 0; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedDiscountType, model.DiscountType); + Assert.Equal(expectedUsageDiscountValue, model.UsageDiscountValue); + Assert.NotNull(model.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, model.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], model.AppliesToPriceIDs[i]); + } + Assert.NotNull(model.Filters); + Assert.Equal(expectedFilters.Count, model.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], model.Filters[i]); + } + Assert.Equal(expectedReason, model.Reason); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedDiscountType = + UsageDiscountDiscountType.Usage; + double expectedUsageDiscountValue = 0; + List expectedAppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"]; + List expectedFilters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ]; + string expectedReason = "reason"; + + Assert.Equal(expectedDiscountType, deserialized.DiscountType); + Assert.Equal(expectedUsageDiscountValue, deserialized.UsageDiscountValue); + Assert.NotNull(deserialized.AppliesToPriceIDs); + Assert.Equal(expectedAppliesToPriceIDs.Count, deserialized.AppliesToPriceIDs.Count); + for (int i = 0; i < expectedAppliesToPriceIDs.Count; i++) + { + Assert.Equal(expectedAppliesToPriceIDs[i], deserialized.AppliesToPriceIDs[i]); + } + Assert.NotNull(deserialized.Filters); + Assert.Equal(expectedFilters.Count, deserialized.Filters.Count); + for (int i = 0; i < expectedFilters.Count; i++) + { + Assert.Equal(expectedFilters[i], deserialized.Filters[i]); + } + Assert.Equal(expectedReason, deserialized.Reason); + } + + [Fact] + public void Validation_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], + Filters = + [ + new() + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }, + ], + Reason = "reason", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesUnsetAreNotSet_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.False(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.False(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.False(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesUnsetValidation_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + }; + + Assert.Null(model.AppliesToPriceIDs); + Assert.True(model.RawData.ContainsKey("applies_to_price_ids")); + Assert.Null(model.Filters); + Assert.True(model.RawData.ContainsKey("filters")); + Assert.Null(model.Reason); + Assert.True(model.RawData.ContainsKey("reason")); + } + + [Fact] + public void OptionalNullablePropertiesSetToNullValidation_Works() + { + var model = new UsageDiscount + { + DiscountType = UsageDiscountDiscountType.Usage, + UsageDiscountValue = 0, + + AppliesToPriceIDs = null, + Filters = null, + Reason = null, + }; + + model.Validate(); + } +} + +public class UsageDiscountDiscountTypeTest : TestBase +{ + [Theory] + [InlineData(UsageDiscountDiscountType.Usage)] + public void Validation_Works(UsageDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UsageDiscountDiscountType.Usage)] + public void SerializationRoundtrip_Works(UsageDiscountDiscountType rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UsageDiscountFilterTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new UsageDiscountFilter + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + ApiEnum expectedField = UsageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + UsageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, model.Field); + Assert.Equal(expectedOperator, model.Operator); + Assert.Equal(expectedValues.Count, model.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], model.Values[i]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new UsageDiscountFilter + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string json = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(json); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new UsageDiscountFilter + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + string element = JsonSerializer.Serialize(model); + var deserialized = JsonSerializer.Deserialize(element); + Assert.NotNull(deserialized); + + ApiEnum expectedField = UsageDiscountFilterField.PriceID; + ApiEnum expectedOperator = + UsageDiscountFilterOperator.Includes; + List expectedValues = ["string"]; + + Assert.Equal(expectedField, deserialized.Field); + Assert.Equal(expectedOperator, deserialized.Operator); + Assert.Equal(expectedValues.Count, deserialized.Values.Count); + for (int i = 0; i < expectedValues.Count; i++) + { + Assert.Equal(expectedValues[i], deserialized.Values[i]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new UsageDiscountFilter + { + Field = UsageDiscountFilterField.PriceID, + Operator = UsageDiscountFilterOperator.Includes, + Values = ["string"], + }; + + model.Validate(); + } +} + +public class UsageDiscountFilterFieldTest : TestBase +{ + [Theory] + [InlineData(UsageDiscountFilterField.PriceID)] + [InlineData(UsageDiscountFilterField.ItemID)] + [InlineData(UsageDiscountFilterField.PriceType)] + [InlineData(UsageDiscountFilterField.Currency)] + [InlineData(UsageDiscountFilterField.PricingUnitID)] + public void Validation_Works(UsageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UsageDiscountFilterField.PriceID)] + [InlineData(UsageDiscountFilterField.ItemID)] + [InlineData(UsageDiscountFilterField.PriceType)] + [InlineData(UsageDiscountFilterField.Currency)] + [InlineData(UsageDiscountFilterField.PricingUnitID)] + public void SerializationRoundtrip_Works(UsageDiscountFilterField rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class UsageDiscountFilterOperatorTest : TestBase +{ + [Theory] + [InlineData(UsageDiscountFilterOperator.Includes)] + [InlineData(UsageDiscountFilterOperator.Excludes)] + public void Validation_Works(UsageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(UsageDiscountFilterOperator.Includes)] + [InlineData(UsageDiscountFilterOperator.Excludes)] + public void SerializationRoundtrip_Works(UsageDiscountFilterOperator rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.Deserialize("\"invalid value\""), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} diff --git a/src/Orb.Tests/Orb.Tests.csproj b/src/Orb.Tests/Orb.Tests.csproj index 50524e44..00c66795 100644 --- a/src/Orb.Tests/Orb.Tests.csproj +++ b/src/Orb.Tests/Orb.Tests.csproj @@ -1,19 +1,23 @@ - - - net8.0 - enable - enable - false - true - - - - - - - - - - - - + + + true + false + Exe + + + net8.0;net472 + + + $(NoWarn),xUnit1004 + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orb.Tests/Service/Alerts/AlertServiceTest.cs b/src/Orb.Tests/Service/Alerts/AlertServiceTest.cs deleted file mode 100644 index f61c0e6c..00000000 --- a/src/Orb.Tests/Service/Alerts/AlertServiceTest.cs +++ /dev/null @@ -1,125 +0,0 @@ -using AlertCreateForCustomerParamsProperties = Orb.Models.Alerts.AlertCreateForCustomerParamsProperties; -using AlertCreateForExternalCustomerParamsProperties = Orb.Models.Alerts.AlertCreateForExternalCustomerParamsProperties; -using AlertCreateForSubscriptionParamsProperties = Orb.Models.Alerts.AlertCreateForSubscriptionParamsProperties; -using Alerts = Orb.Models.Alerts; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Alerts; - -public class AlertServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Retrieve_Works() - { - var alert = await this.client.Alerts.Retrieve( - new Alerts::AlertRetrieveParams() { AlertID = "alert_id" } - ); - alert.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var alert = await this.client.Alerts.Update( - new Alerts::AlertUpdateParams() - { - AlertConfigurationID = "alert_configuration_id", - Thresholds = [new Alerts::Threshold() { Value = 0 }], - } - ); - alert.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Alerts.List( - new Alerts::AlertListParams() - { - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - CustomerID = "customer_id", - ExternalCustomerID = "external_customer_id", - Limit = 1, - SubscriptionID = "subscription_id", - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task CreateForCustomer_Works() - { - var alert = await this.client.Alerts.CreateForCustomer( - new Alerts::AlertCreateForCustomerParams() - { - CustomerID = "customer_id", - Currency = "currency", - Type = AlertCreateForCustomerParamsProperties::Type.CreditBalanceDepleted, - Thresholds = [new Alerts::Threshold() { Value = 0 }], - } - ); - alert.Validate(); - } - - [Fact] - public async Tasks::Task CreateForExternalCustomer_Works() - { - var alert = await this.client.Alerts.CreateForExternalCustomer( - new Alerts::AlertCreateForExternalCustomerParams() - { - ExternalCustomerID = "external_customer_id", - Currency = "currency", - Type = AlertCreateForExternalCustomerParamsProperties::Type.CreditBalanceDepleted, - Thresholds = [new Alerts::Threshold() { Value = 0 }], - } - ); - alert.Validate(); - } - - [Fact] - public async Tasks::Task CreateForSubscription_Works() - { - var alert = await this.client.Alerts.CreateForSubscription( - new Alerts::AlertCreateForSubscriptionParams() - { - SubscriptionID = "subscription_id", - Thresholds = [new Alerts::Threshold() { Value = 0 }], - Type = AlertCreateForSubscriptionParamsProperties::Type.UsageExceeded, - MetricID = "metric_id", - } - ); - alert.Validate(); - } - - [Fact] - public async Tasks::Task Disable_Works() - { - var alert = await this.client.Alerts.Disable( - new Alerts::AlertDisableParams() - { - AlertConfigurationID = "alert_configuration_id", - SubscriptionID = "subscription_id", - } - ); - alert.Validate(); - } - - [Fact] - public async Tasks::Task Enable_Works() - { - var alert = await this.client.Alerts.Enable( - new Alerts::AlertEnableParams() - { - AlertConfigurationID = "alert_configuration_id", - SubscriptionID = "subscription_id", - } - ); - alert.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Beta/BetaServiceTest.cs b/src/Orb.Tests/Service/Beta/BetaServiceTest.cs deleted file mode 100644 index 1cb8bc4a..00000000 --- a/src/Orb.Tests/Service/Beta/BetaServiceTest.cs +++ /dev/null @@ -1,283 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddAdjustmentProperties; -using AddPriceProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddPriceProperties; -using Beta = Orb.Models.Beta; -using BetaCreatePlanVersionParamsProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; -using CustomExpirationProperties = Orb.Models.CustomExpirationProperties; -using Models = Orb.Models; -using NewAllocationPriceProperties = Orb.Models.NewAllocationPriceProperties; -using NewBillingCycleConfigurationProperties = Orb.Models.NewBillingCycleConfigurationProperties; -using NewPercentageDiscountProperties = Orb.Models.NewPercentageDiscountProperties; -using NewPlanUnitPriceProperties = Orb.Models.NewPlanUnitPriceProperties; -using ReplaceAdjustmentProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; -using ReplacePriceProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplacePriceProperties; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TransformPriceFilterProperties = Orb.Models.TransformPriceFilterProperties; -using UnitConversionRateConfigProperties = Orb.Models.UnitConversionRateConfigProperties; - -namespace Orb.Tests.Service.Beta; - -public class BetaServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task CreatePlanVersion_Works() - { - var planVersion = await this.client.Beta.CreatePlanVersion( - new Beta::BetaCreatePlanVersionParams() - { - PlanID = "plan_id", - Version = 0, - AddAdjustments = - [ - new BetaCreatePlanVersionParamsProperties::AddAdjustment() - { - Adjustment = AddAdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - PlanPhaseOrder = 0, - }, - ], - AddPrices = - [ - new BetaCreatePlanVersionParamsProperties::AddPrice() - { - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - PlanPhaseOrder = 0, - Price = AddPriceProperties::Price.Create( - new Models::NewPlanUnitPrice() - { - Cadence = NewPlanUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewPlanUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewPlanUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - }, - ], - RemoveAdjustments = - [ - new BetaCreatePlanVersionParamsProperties::RemoveAdjustment() - { - AdjustmentID = "adjustment_id", - PlanPhaseOrder = 0, - }, - ], - RemovePrices = - [ - new BetaCreatePlanVersionParamsProperties::RemovePrice() - { - PriceID = "price_id", - PlanPhaseOrder = 0, - }, - ], - ReplaceAdjustments = - [ - new BetaCreatePlanVersionParamsProperties::ReplaceAdjustment() - { - Adjustment = ReplaceAdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - ReplacesAdjustmentID = "replaces_adjustment_id", - PlanPhaseOrder = 0, - }, - ], - ReplacePrices = - [ - new BetaCreatePlanVersionParamsProperties::ReplacePrice() - { - ReplacesPriceID = "replaces_price_id", - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - PlanPhaseOrder = 0, - Price = ReplacePriceProperties::Price.Create( - new Models::NewPlanUnitPrice() - { - Cadence = NewPlanUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewPlanUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewPlanUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - }, - ], - SetAsDefault = true, - } - ); - planVersion.Validate(); - } - - [Fact] - public async Tasks::Task FetchPlanVersion_Works() - { - var planVersion = await this.client.Beta.FetchPlanVersion( - new Beta::BetaFetchPlanVersionParams() { PlanID = "plan_id", Version = "version" } - ); - planVersion.Validate(); - } - - [Fact] - public async Tasks::Task SetDefaultPlanVersion_Works() - { - var plan = await this.client.Beta.SetDefaultPlanVersion( - new Beta::BetaSetDefaultPlanVersionParams() { PlanID = "plan_id", Version = 0 } - ); - plan.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Beta/ExternalPlanID/ExternalPlanIDServiceTest.cs b/src/Orb.Tests/Service/Beta/ExternalPlanID/ExternalPlanIDServiceTest.cs deleted file mode 100644 index 8db84ab8..00000000 --- a/src/Orb.Tests/Service/Beta/ExternalPlanID/ExternalPlanIDServiceTest.cs +++ /dev/null @@ -1,291 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddAdjustmentProperties; -using AddPriceProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddPriceProperties; -using CustomExpirationProperties = Orb.Models.CustomExpirationProperties; -using ExternalPlanID = Orb.Models.Beta.ExternalPlanID; -using ExternalPlanIDCreatePlanVersionParamsProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; -using Models = Orb.Models; -using NewAllocationPriceProperties = Orb.Models.NewAllocationPriceProperties; -using NewBillingCycleConfigurationProperties = Orb.Models.NewBillingCycleConfigurationProperties; -using NewPercentageDiscountProperties = Orb.Models.NewPercentageDiscountProperties; -using NewPlanUnitPriceProperties = Orb.Models.NewPlanUnitPriceProperties; -using ReplaceAdjustmentProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; -using ReplacePriceProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplacePriceProperties; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TransformPriceFilterProperties = Orb.Models.TransformPriceFilterProperties; -using UnitConversionRateConfigProperties = Orb.Models.UnitConversionRateConfigProperties; - -namespace Orb.Tests.Service.Beta.ExternalPlanID; - -public class ExternalPlanIDServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task CreatePlanVersion_Works() - { - var planVersion = await this.client.Beta.ExternalPlanID.CreatePlanVersion( - new ExternalPlanID::ExternalPlanIDCreatePlanVersionParams() - { - ExternalPlanID = "external_plan_id", - Version = 0, - AddAdjustments = - [ - new ExternalPlanIDCreatePlanVersionParamsProperties::AddAdjustment() - { - Adjustment = AddAdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - PlanPhaseOrder = 0, - }, - ], - AddPrices = - [ - new ExternalPlanIDCreatePlanVersionParamsProperties::AddPrice() - { - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - PlanPhaseOrder = 0, - Price = AddPriceProperties::Price.Create( - new Models::NewPlanUnitPrice() - { - Cadence = NewPlanUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewPlanUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewPlanUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - }, - ], - RemoveAdjustments = - [ - new ExternalPlanIDCreatePlanVersionParamsProperties::RemoveAdjustment() - { - AdjustmentID = "adjustment_id", - PlanPhaseOrder = 0, - }, - ], - RemovePrices = - [ - new ExternalPlanIDCreatePlanVersionParamsProperties::RemovePrice() - { - PriceID = "price_id", - PlanPhaseOrder = 0, - }, - ], - ReplaceAdjustments = - [ - new ExternalPlanIDCreatePlanVersionParamsProperties::ReplaceAdjustment() - { - Adjustment = ReplaceAdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - ReplacesAdjustmentID = "replaces_adjustment_id", - PlanPhaseOrder = 0, - }, - ], - ReplacePrices = - [ - new ExternalPlanIDCreatePlanVersionParamsProperties::ReplacePrice() - { - ReplacesPriceID = "replaces_price_id", - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - PlanPhaseOrder = 0, - Price = ReplacePriceProperties::Price.Create( - new Models::NewPlanUnitPrice() - { - Cadence = NewPlanUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewPlanUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewPlanUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - }, - ], - SetAsDefault = true, - } - ); - planVersion.Validate(); - } - - [Fact] - public async Tasks::Task FetchPlanVersion_Works() - { - var planVersion = await this.client.Beta.ExternalPlanID.FetchPlanVersion( - new ExternalPlanID::ExternalPlanIDFetchPlanVersionParams() - { - ExternalPlanID = "external_plan_id", - Version = "version", - } - ); - planVersion.Validate(); - } - - [Fact] - public async Tasks::Task SetDefaultPlanVersion_Works() - { - var plan = await this.client.Beta.ExternalPlanID.SetDefaultPlanVersion( - new ExternalPlanID::ExternalPlanIDSetDefaultPlanVersionParams() - { - ExternalPlanID = "external_plan_id", - Version = 0, - } - ); - plan.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Coupons/CouponServiceTest.cs b/src/Orb.Tests/Service/Coupons/CouponServiceTest.cs deleted file mode 100644 index 3cd0d032..00000000 --- a/src/Orb.Tests/Service/Coupons/CouponServiceTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -using CouponCreateParamsProperties = Orb.Models.Coupons.CouponCreateParamsProperties; -using Coupons = Orb.Models.Coupons; -using DiscountProperties = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties; -using PercentageProperties = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties.PercentageProperties; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Coupons; - -public class CouponServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var coupon = await this.client.Coupons.Create( - new Coupons::CouponCreateParams() - { - Discount = CouponCreateParamsProperties::Discount.Create( - new DiscountProperties::Percentage() - { - DiscountType = PercentageProperties::DiscountType.Percentage, - PercentageDiscount = 0, - } - ), - RedemptionCode = "HALFOFF", - DurationInMonths = 12, - MaxRedemptions = 1, - } - ); - coupon.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Coupons.List( - new Coupons::CouponListParams() - { - Cursor = "cursor", - Limit = 1, - RedemptionCode = "redemption_code", - ShowArchived = true, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Archive_Works() - { - var coupon = await this.client.Coupons.Archive( - new Coupons::CouponArchiveParams() { CouponID = "coupon_id" } - ); - coupon.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var coupon = await this.client.Coupons.Fetch( - new Coupons::CouponFetchParams() { CouponID = "coupon_id" } - ); - coupon.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Coupons/Subscriptions/SubscriptionServiceTest.cs b/src/Orb.Tests/Service/Coupons/Subscriptions/SubscriptionServiceTest.cs deleted file mode 100644 index bbdbc07f..00000000 --- a/src/Orb.Tests/Service/Coupons/Subscriptions/SubscriptionServiceTest.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Subscriptions = Orb.Models.Coupons.Subscriptions; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Coupons.Subscriptions; - -public class SubscriptionServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Coupons.Subscriptions.List( - new Subscriptions::SubscriptionListParams() - { - CouponID = "coupon_id", - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } -} diff --git a/src/Orb.Tests/Service/CreditNotes/CreditNoteServiceTest.cs b/src/Orb.Tests/Service/CreditNotes/CreditNoteServiceTest.cs deleted file mode 100644 index c664efc3..00000000 --- a/src/Orb.Tests/Service/CreditNotes/CreditNoteServiceTest.cs +++ /dev/null @@ -1,61 +0,0 @@ -using CreditNoteCreateParamsProperties = Orb.Models.CreditNotes.CreditNoteCreateParamsProperties; -using CreditNotes = Orb.Models.CreditNotes; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.CreditNotes; - -public class CreditNoteServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var creditNote = await this.client.CreditNotes.Create( - new CreditNotes::CreditNoteCreateParams() - { - LineItems = - [ - new CreditNoteCreateParamsProperties::LineItem() - { - Amount = "amount", - InvoiceLineItemID = "4khy3nwzktxv7", - EndDate = System::DateOnly.Parse("2023-09-22"), - StartDate = System::DateOnly.Parse("2023-09-22"), - }, - ], - Reason = CreditNoteCreateParamsProperties::Reason.Duplicate, - EndDate = System::DateOnly.Parse("2023-09-22"), - Memo = "An optional memo for my credit note.", - StartDate = System::DateOnly.Parse("2023-09-22"), - } - ); - creditNote.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.CreditNotes.List( - new CreditNotes::CreditNoteListParams() - { - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var creditNote = await this.client.CreditNotes.Fetch( - new CreditNotes::CreditNoteFetchParams() { CreditNoteID = "credit_note_id" } - ); - creditNote.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Customers/BalanceTransactions/BalanceTransactionServiceTest.cs b/src/Orb.Tests/Service/Customers/BalanceTransactions/BalanceTransactionServiceTest.cs deleted file mode 100644 index dce54a80..00000000 --- a/src/Orb.Tests/Service/Customers/BalanceTransactions/BalanceTransactionServiceTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -using BalanceTransactionCreateParamsProperties = Orb.Models.Customers.BalanceTransactions.BalanceTransactionCreateParamsProperties; -using BalanceTransactions = Orb.Models.Customers.BalanceTransactions; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Customers.BalanceTransactions; - -public class BalanceTransactionServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var balanceTransaction = await this.client.Customers.BalanceTransactions.Create( - new BalanceTransactions::BalanceTransactionCreateParams() - { - CustomerID = "customer_id", - Amount = "amount", - Type = BalanceTransactionCreateParamsProperties::Type.Increment, - Description = "description", - } - ); - balanceTransaction.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Customers.BalanceTransactions.List( - new BalanceTransactions::BalanceTransactionListParams() - { - CustomerID = "customer_id", - Cursor = "cursor", - Limit = 1, - OperationTimeGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - OperationTimeGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - OperationTimeLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - OperationTimeLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - } - ); - page.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Customers/Costs/CostServiceTest.cs b/src/Orb.Tests/Service/Customers/Costs/CostServiceTest.cs deleted file mode 100644 index 3a93c5da..00000000 --- a/src/Orb.Tests/Service/Customers/Costs/CostServiceTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -using CostListByExternalIDParamsProperties = Orb.Models.Customers.Costs.CostListByExternalIDParamsProperties; -using CostListParamsProperties = Orb.Models.Customers.Costs.CostListParamsProperties; -using Costs = Orb.Models.Customers.Costs; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Customers.Costs; - -public class CostServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task List_Works() - { - var costs = await this.client.Customers.Costs.List( - new Costs::CostListParams() - { - CustomerID = "customer_id", - Currency = "currency", - TimeframeEnd = System::DateTime.Parse("2022-03-01T05:00:00Z"), - TimeframeStart = System::DateTime.Parse("2022-02-01T05:00:00Z"), - ViewMode = CostListParamsProperties::ViewMode.Periodic, - } - ); - costs.Validate(); - } - - [Fact] - public async Tasks::Task ListByExternalID_Works() - { - var response = await this.client.Customers.Costs.ListByExternalID( - new Costs::CostListByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - Currency = "currency", - TimeframeEnd = System::DateTime.Parse("2022-03-01T05:00:00Z"), - TimeframeStart = System::DateTime.Parse("2022-02-01T05:00:00Z"), - ViewMode = CostListByExternalIDParamsProperties::ViewMode.Periodic, - } - ); - response.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Customers/Credits/CreditServiceTest.cs b/src/Orb.Tests/Service/Customers/Credits/CreditServiceTest.cs deleted file mode 100644 index 9acd43d4..00000000 --- a/src/Orb.Tests/Service/Customers/Credits/CreditServiceTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Credits = Orb.Models.Customers.Credits; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Customers.Credits; - -public class CreditServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Customers.Credits.List( - new Credits::CreditListParams() - { - CustomerID = "customer_id", - Currency = "currency", - Cursor = "cursor", - IncludeAllBlocks = true, - Limit = 1, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task ListByExternalID_Works() - { - var page = await this.client.Customers.Credits.ListByExternalID( - new Credits::CreditListByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - Currency = "currency", - Cursor = "cursor", - IncludeAllBlocks = true, - Limit = 1, - } - ); - page.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Customers/Credits/Ledger/LedgerServiceTest.cs b/src/Orb.Tests/Service/Customers/Credits/Ledger/LedgerServiceTest.cs deleted file mode 100644 index 3d01de1c..00000000 --- a/src/Orb.Tests/Service/Customers/Credits/Ledger/LedgerServiceTest.cs +++ /dev/null @@ -1,133 +0,0 @@ -using BodyProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; -using BodyProperties1 = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; -using IncrementProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties; -using IncrementProperties1 = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties; -using InvoiceSettingsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; -using InvoiceSettingsProperties1 = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; -using Ledger = Orb.Models.Customers.Credits.Ledger; -using LedgerCreateEntryByExternalIDParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties; -using LedgerCreateEntryParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties; -using LedgerListByExternalIDParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDParamsProperties; -using LedgerListParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerListParamsProperties; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Customers.Credits.Ledger; - -public class LedgerServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Customers.Credits.Ledger.List( - new Ledger::LedgerListParams() - { - CustomerID = "customer_id", - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Currency = "currency", - Cursor = "cursor", - EntryStatus = LedgerListParamsProperties::EntryStatus.Committed, - EntryType = LedgerListParamsProperties::EntryType.Increment, - Limit = 1, - MinimumAmount = "minimum_amount", - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task CreateEntry_Works() - { - var response = await this.client.Customers.Credits.Ledger.CreateEntry( - new Ledger::LedgerCreateEntryParams() - { - CustomerID = "customer_id", - Body = LedgerCreateEntryParamsProperties::Body.Create( - new BodyProperties::Increment() - { - Amount = 0, - EntryType = IncrementProperties::EntryType.Increment, - Currency = "currency", - Description = "description", - EffectiveDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExpiryDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - InvoiceSettings = new IncrementProperties::InvoiceSettings() - { - AutoCollection = true, - NetTerms = 0, - InvoiceDate = InvoiceSettingsProperties::InvoiceDate.Create( - System::DateOnly.Parse("2019-12-27") - ), - Memo = "memo", - RequireSuccessfulPayment = true, - }, - Metadata = new() { { "foo", "string" } }, - PerUnitCostBasis = "per_unit_cost_basis", - } - ), - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task CreateEntryByExternalID_Works() - { - var response = await this.client.Customers.Credits.Ledger.CreateEntryByExternalID( - new Ledger::LedgerCreateEntryByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - Body = LedgerCreateEntryByExternalIDParamsProperties::Body.Create( - new BodyProperties1::Increment() - { - Amount = 0, - EntryType = IncrementProperties1::EntryType.Increment, - Currency = "currency", - Description = "description", - EffectiveDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExpiryDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - InvoiceSettings = new IncrementProperties1::InvoiceSettings() - { - AutoCollection = true, - NetTerms = 0, - InvoiceDate = InvoiceSettingsProperties1::InvoiceDate.Create( - System::DateOnly.Parse("2019-12-27") - ), - Memo = "memo", - RequireSuccessfulPayment = true, - }, - Metadata = new() { { "foo", "string" } }, - PerUnitCostBasis = "per_unit_cost_basis", - } - ), - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task ListByExternalID_Works() - { - var page = await this.client.Customers.Credits.Ledger.ListByExternalID( - new Ledger::LedgerListByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Currency = "currency", - Cursor = "cursor", - EntryStatus = LedgerListByExternalIDParamsProperties::EntryStatus.Committed, - EntryType = LedgerListByExternalIDParamsProperties::EntryType.Increment, - Limit = 1, - MinimumAmount = "minimum_amount", - } - ); - page.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Customers/Credits/TopUps/TopUpServiceTest.cs b/src/Orb.Tests/Service/Customers/Credits/TopUps/TopUpServiceTest.cs deleted file mode 100644 index 2879cb61..00000000 --- a/src/Orb.Tests/Service/Customers/Credits/TopUps/TopUpServiceTest.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TopUpCreateByExternalIDParamsProperties = Orb.Models.Customers.Credits.TopUps.TopUpCreateByExternalIDParamsProperties; -using TopUpCreateParamsProperties = Orb.Models.Customers.Credits.TopUps.TopUpCreateParamsProperties; -using TopUps = Orb.Models.Customers.Credits.TopUps; - -namespace Orb.Tests.Service.Customers.Credits.TopUps; - -public class TopUpServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var topUp = await this.client.Customers.Credits.TopUps.Create( - new TopUps::TopUpCreateParams() - { - CustomerID = "customer_id", - Amount = "amount", - Currency = "currency", - InvoiceSettings = new TopUpCreateParamsProperties::InvoiceSettings() - { - AutoCollection = true, - NetTerms = 0, - Memo = "memo", - RequireSuccessfulPayment = true, - }, - PerUnitCostBasis = "per_unit_cost_basis", - Threshold = "threshold", - ActiveFrom = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExpiresAfter = 0, - ExpiresAfterUnit = TopUpCreateParamsProperties::ExpiresAfterUnit.Day, - } - ); - topUp.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Customers.Credits.TopUps.List( - new TopUps::TopUpListParams() - { - CustomerID = "customer_id", - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Delete_Works() - { - await this.client.Customers.Credits.TopUps.Delete( - new TopUps::TopUpDeleteParams() { CustomerID = "customer_id", TopUpID = "top_up_id" } - ); - } - - [Fact] - public async Tasks::Task CreateByExternalID_Works() - { - var response = await this.client.Customers.Credits.TopUps.CreateByExternalID( - new TopUps::TopUpCreateByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - Amount = "amount", - Currency = "currency", - InvoiceSettings = new TopUpCreateByExternalIDParamsProperties::InvoiceSettings() - { - AutoCollection = true, - NetTerms = 0, - Memo = "memo", - RequireSuccessfulPayment = true, - }, - PerUnitCostBasis = "per_unit_cost_basis", - Threshold = "threshold", - ActiveFrom = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExpiresAfter = 0, - ExpiresAfterUnit = TopUpCreateByExternalIDParamsProperties::ExpiresAfterUnit.Day, - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task DeleteByExternalID_Works() - { - await this.client.Customers.Credits.TopUps.DeleteByExternalID( - new TopUps::TopUpDeleteByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - TopUpID = "top_up_id", - } - ); - } - - [Fact] - public async Tasks::Task ListByExternalID_Works() - { - var page = await this.client.Customers.Credits.TopUps.ListByExternalID( - new TopUps::TopUpListByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Customers/CustomerServiceTest.cs b/src/Orb.Tests/Service/Customers/CustomerServiceTest.cs deleted file mode 100644 index 96dbc5fe..00000000 --- a/src/Orb.Tests/Service/Customers/CustomerServiceTest.cs +++ /dev/null @@ -1,310 +0,0 @@ -using CustomerCreateParamsProperties = Orb.Models.Customers.CustomerCreateParamsProperties; -using Customers = Orb.Models.Customers; -using CustomerTaxIDProperties = Orb.Models.CustomerTaxIDProperties; -using CustomerUpdateByExternalIDParamsProperties = Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties; -using CustomerUpdateParamsProperties = Orb.Models.Customers.CustomerUpdateParamsProperties; -using Models = Orb.Models; -using NewAvalaraTaxConfigurationProperties = Orb.Models.Customers.NewAvalaraTaxConfigurationProperties; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Customers; - -public class CustomerServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var customer = await this.client.Customers.Create( - new Customers::CustomerCreateParams() - { - Email = "dev@stainless.com", - Name = "x", - AccountingSyncConfiguration = new Customers::NewAccountingSyncConfiguration() - { - AccountingProviders = - [ - new Customers::AccountingProviderConfig() - { - ExternalProviderID = "external_provider_id", - ProviderType = "provider_type", - }, - ], - Excluded = true, - }, - AdditionalEmails = ["dev@stainless.com"], - AutoCollection = true, - BillingAddress = new Customers::AddressInput() - { - City = "city", - Country = "country", - Line1 = "line1", - Line2 = "line2", - PostalCode = "postal_code", - State = "state", - }, - Currency = "currency", - EmailDelivery = true, - ExternalCustomerID = "external_customer_id", - Hierarchy = new Customers::CustomerHierarchyConfig() - { - ChildCustomerIDs = ["string"], - ParentCustomerID = "parent_customer_id", - }, - Metadata = new() { { "foo", "string" } }, - PaymentProvider = CustomerCreateParamsProperties::PaymentProvider.Quickbooks, - PaymentProviderID = "payment_provider_id", - ReportingConfiguration = new Customers::NewReportingConfiguration() - { - Exempt = true, - }, - ShippingAddress = new Customers::AddressInput() - { - City = "city", - Country = "country", - Line1 = "line1", - Line2 = "line2", - PostalCode = "postal_code", - State = "state", - }, - TaxConfiguration = CustomerCreateParamsProperties::TaxConfiguration.Create( - new Customers::NewAvalaraTaxConfiguration() - { - TaxExempt = true, - TaxProvider = NewAvalaraTaxConfigurationProperties::TaxProvider.Avalara, - TaxExemptionCode = "tax_exemption_code", - } - ), - TaxID = new Models::CustomerTaxID() - { - Country = CustomerTaxIDProperties::Country.Ad, - Type = CustomerTaxIDProperties::Type.AdNrt, - Value = "value", - }, - Timezone = "timezone", - } - ); - customer.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var customer = await this.client.Customers.Update( - new Customers::CustomerUpdateParams() - { - CustomerID = "customer_id", - AccountingSyncConfiguration = new Customers::NewAccountingSyncConfiguration() - { - AccountingProviders = - [ - new Customers::AccountingProviderConfig() - { - ExternalProviderID = "external_provider_id", - ProviderType = "provider_type", - }, - ], - Excluded = true, - }, - AdditionalEmails = ["string"], - AutoCollection = true, - BillingAddress = new Customers::AddressInput() - { - City = "city", - Country = "country", - Line1 = "line1", - Line2 = "line2", - PostalCode = "postal_code", - State = "state", - }, - Currency = "currency", - Email = "dev@stainless.com", - EmailDelivery = true, - ExternalCustomerID = "external_customer_id", - Hierarchy = new Customers::CustomerHierarchyConfig() - { - ChildCustomerIDs = ["string"], - ParentCustomerID = "parent_customer_id", - }, - Metadata = new() { { "foo", "string" } }, - Name = "name", - PaymentProvider = CustomerUpdateParamsProperties::PaymentProvider.Quickbooks, - PaymentProviderID = "payment_provider_id", - ReportingConfiguration = new Customers::NewReportingConfiguration() - { - Exempt = true, - }, - ShippingAddress = new Customers::AddressInput() - { - City = "city", - Country = "country", - Line1 = "line1", - Line2 = "line2", - PostalCode = "postal_code", - State = "state", - }, - TaxConfiguration = CustomerUpdateParamsProperties::TaxConfiguration.Create( - new Customers::NewAvalaraTaxConfiguration() - { - TaxExempt = true, - TaxProvider = NewAvalaraTaxConfigurationProperties::TaxProvider.Avalara, - TaxExemptionCode = "tax_exemption_code", - } - ), - TaxID = new Models::CustomerTaxID() - { - Country = CustomerTaxIDProperties::Country.Ad, - Type = CustomerTaxIDProperties::Type.AdNrt, - Value = "value", - }, - } - ); - customer.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Customers.List( - new Customers::CustomerListParams() - { - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Delete_Works() - { - await this.client.Customers.Delete( - new Customers::CustomerDeleteParams() { CustomerID = "customer_id" } - ); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var customer = await this.client.Customers.Fetch( - new Customers::CustomerFetchParams() { CustomerID = "customer_id" } - ); - customer.Validate(); - } - - [Fact] - public async Tasks::Task FetchByExternalID_Works() - { - var customer = await this.client.Customers.FetchByExternalID( - new Customers::CustomerFetchByExternalIDParams() - { - ExternalCustomerID = "external_customer_id", - } - ); - customer.Validate(); - } - - [Fact] - public async Tasks::Task SyncPaymentMethodsFromGateway_Works() - { - await this.client.Customers.SyncPaymentMethodsFromGateway( - new Customers::CustomerSyncPaymentMethodsFromGatewayParams() - { - CustomerID = "customer_id", - } - ); - } - - [Fact] - public async Tasks::Task SyncPaymentMethodsFromGatewayByExternalCustomerID_Works() - { - await this.client.Customers.SyncPaymentMethodsFromGatewayByExternalCustomerID( - new Customers::CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams() - { - ExternalCustomerID = "external_customer_id", - } - ); - } - - [Fact] - public async Tasks::Task UpdateByExternalID_Works() - { - var customer = await this.client.Customers.UpdateByExternalID( - new Customers::CustomerUpdateByExternalIDParams() - { - ID = "external_customer_id", - AccountingSyncConfiguration = new Customers::NewAccountingSyncConfiguration() - { - AccountingProviders = - [ - new Customers::AccountingProviderConfig() - { - ExternalProviderID = "external_provider_id", - ProviderType = "provider_type", - }, - ], - Excluded = true, - }, - AdditionalEmails = ["string"], - AutoCollection = true, - BillingAddress = new Customers::AddressInput() - { - City = "city", - Country = "country", - Line1 = "line1", - Line2 = "line2", - PostalCode = "postal_code", - State = "state", - }, - Currency = "currency", - Email = "dev@stainless.com", - EmailDelivery = true, - ExternalCustomerID = "external_customer_id", - Hierarchy = new Customers::CustomerHierarchyConfig() - { - ChildCustomerIDs = ["string"], - ParentCustomerID = "parent_customer_id", - }, - Metadata = new() { { "foo", "string" } }, - Name = "name", - PaymentProvider = - CustomerUpdateByExternalIDParamsProperties::PaymentProvider.Quickbooks, - PaymentProviderID = "payment_provider_id", - ReportingConfiguration = new Customers::NewReportingConfiguration() - { - Exempt = true, - }, - ShippingAddress = new Customers::AddressInput() - { - City = "city", - Country = "country", - Line1 = "line1", - Line2 = "line2", - PostalCode = "postal_code", - State = "state", - }, - TaxConfiguration = - CustomerUpdateByExternalIDParamsProperties::TaxConfiguration.Create( - new Customers::NewAvalaraTaxConfiguration() - { - TaxExempt = true, - TaxProvider = NewAvalaraTaxConfigurationProperties::TaxProvider.Avalara, - TaxExemptionCode = "tax_exemption_code", - } - ), - TaxID = new Models::CustomerTaxID() - { - Country = CustomerTaxIDProperties::Country.Ad, - Type = CustomerTaxIDProperties::Type.AdNrt, - Value = "value", - }, - } - ); - customer.Validate(); - } -} diff --git a/src/Orb.Tests/Service/DimensionalPriceGroups/DimensionalPriceGroupServiceTest.cs b/src/Orb.Tests/Service/DimensionalPriceGroups/DimensionalPriceGroupServiceTest.cs deleted file mode 100644 index 64882f8f..00000000 --- a/src/Orb.Tests/Service/DimensionalPriceGroups/DimensionalPriceGroupServiceTest.cs +++ /dev/null @@ -1,49 +0,0 @@ -using DimensionalPriceGroups = Orb.Models.DimensionalPriceGroups; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.DimensionalPriceGroups; - -public class DimensionalPriceGroupServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var dimensionalPriceGroup = await this.client.DimensionalPriceGroups.Create( - new DimensionalPriceGroups::DimensionalPriceGroupCreateParams() - { - BillableMetricID = "billable_metric_id", - Dimensions = ["region", "instance_type"], - Name = "name", - ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", - Metadata = new() { { "foo", "string" } }, - } - ); - dimensionalPriceGroup.Validate(); - } - - [Fact] - public async Tasks::Task Retrieve_Works() - { - var dimensionalPriceGroup = await this.client.DimensionalPriceGroups.Retrieve( - new DimensionalPriceGroups::DimensionalPriceGroupRetrieveParams() - { - DimensionalPriceGroupID = "dimensional_price_group_id", - } - ); - dimensionalPriceGroup.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.DimensionalPriceGroups.List( - new DimensionalPriceGroups::DimensionalPriceGroupListParams() - { - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } -} diff --git a/src/Orb.Tests/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDServiceTest.cs b/src/Orb.Tests/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDServiceTest.cs deleted file mode 100644 index 204fb06e..00000000 --- a/src/Orb.Tests/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDServiceTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ExternalDimensionalPriceGroupID = Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; - -public class ExternalDimensionalPriceGroupIDServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Retrieve_Works() - { - var dimensionalPriceGroup = - await this.client.DimensionalPriceGroups.ExternalDimensionalPriceGroupID.Retrieve( - new ExternalDimensionalPriceGroupID::ExternalDimensionalPriceGroupIDRetrieveParams() - { - ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", - } - ); - dimensionalPriceGroup.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Events/Backfills/BackfillServiceTest.cs b/src/Orb.Tests/Service/Events/Backfills/BackfillServiceTest.cs deleted file mode 100644 index 4f98d59e..00000000 --- a/src/Orb.Tests/Service/Events/Backfills/BackfillServiceTest.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Backfills = Orb.Models.Events.Backfills; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Events.Backfills; - -public class BackfillServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var backfill = await this.client.Events.Backfills.Create( - new Backfills::BackfillCreateParams() - { - TimeframeEnd = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - TimeframeStart = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CloseTime = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CustomerID = "customer_id", - DeprecationFilter = "my_numeric_property > 100 AND my_other_property = 'bar'", - ExternalCustomerID = "external_customer_id", - ReplaceExistingEvents = true, - } - ); - backfill.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Events.Backfills.List( - new Backfills::BackfillListParams() { Cursor = "cursor", Limit = 1 } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Close_Works() - { - var response = await this.client.Events.Backfills.Close( - new Backfills::BackfillCloseParams() { BackfillID = "backfill_id" } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var response = await this.client.Events.Backfills.Fetch( - new Backfills::BackfillFetchParams() { BackfillID = "backfill_id" } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Revert_Works() - { - var response = await this.client.Events.Backfills.Revert( - new Backfills::BackfillRevertParams() { BackfillID = "backfill_id" } - ); - response.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Events/EventServiceTest.cs b/src/Orb.Tests/Service/Events/EventServiceTest.cs deleted file mode 100644 index 588c0abe..00000000 --- a/src/Orb.Tests/Service/Events/EventServiceTest.cs +++ /dev/null @@ -1,79 +0,0 @@ -using EventIngestParamsProperties = Orb.Models.Events.EventIngestParamsProperties; -using Events = Orb.Models.Events; -using Json = System.Text.Json; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Events; - -public class EventServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Update_Works() - { - var event1 = await this.client.Events.Update( - new Events::EventUpdateParams() - { - EventID = "event_id", - EventName = "event_name", - Properties = new() { { "foo", Json::JsonSerializer.SerializeToElement("bar") } }, - Timestamp = System::DateTime.Parse("2020-12-09T16:09:53Z"), - CustomerID = "customer_id", - ExternalCustomerID = "external_customer_id", - } - ); - event1.Validate(); - } - - [Fact] - public async Tasks::Task Deprecate_Works() - { - var response = await this.client.Events.Deprecate( - new Events::EventDeprecateParams() { EventID = "event_id" } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Ingest_Works() - { - var response = await this.client.Events.Ingest( - new Events::EventIngestParams() - { - Events = - [ - new EventIngestParamsProperties::Event() - { - EventName = "event_name", - IdempotencyKey = "idempotency_key", - Properties1 = new() - { - { "foo", Json::JsonSerializer.SerializeToElement("bar") }, - }, - Timestamp = System::DateTime.Parse("2020-12-09T16:09:53Z"), - CustomerID = "customer_id", - ExternalCustomerID = "external_customer_id", - }, - ], - BackfillID = "backfill_id", - Debug = true, - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Search_Works() - { - var response = await this.client.Events.Search( - new Events::EventSearchParams() - { - EventIDs = ["string"], - TimeframeEnd = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - TimeframeStart = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - } - ); - response.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Events/Volume/VolumeServiceTest.cs b/src/Orb.Tests/Service/Events/Volume/VolumeServiceTest.cs deleted file mode 100644 index 39f034e5..00000000 --- a/src/Orb.Tests/Service/Events/Volume/VolumeServiceTest.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using Volume = Orb.Models.Events.Volume; - -namespace Orb.Tests.Service.Events.Volume; - -public class VolumeServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task List_Works() - { - var eventVolumes = await this.client.Events.Volume.List( - new Volume::VolumeListParams() - { - TimeframeStart = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - Limit = 1, - TimeframeEnd = System::DateTime.Parse("2024-10-11T06:00:00Z"), - } - ); - eventVolumes.Validate(); - } -} diff --git a/src/Orb.Tests/Service/InvoiceLineItems/InvoiceLineItemServiceTest.cs b/src/Orb.Tests/Service/InvoiceLineItems/InvoiceLineItemServiceTest.cs deleted file mode 100644 index 4f1453ec..00000000 --- a/src/Orb.Tests/Service/InvoiceLineItems/InvoiceLineItemServiceTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -using InvoiceLineItems = Orb.Models.InvoiceLineItems; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.InvoiceLineItems; - -public class InvoiceLineItemServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var invoiceLineItem = await this.client.InvoiceLineItems.Create( - new InvoiceLineItems::InvoiceLineItemCreateParams() - { - Amount = "12.00", - EndDate = System::DateOnly.Parse("2023-09-22"), - InvoiceID = "4khy3nwzktxv7", - Name = "Item Name", - Quantity = 1, - StartDate = System::DateOnly.Parse("2023-09-22"), - } - ); - invoiceLineItem.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Invoices/InvoiceServiceTest.cs b/src/Orb.Tests/Service/Invoices/InvoiceServiceTest.cs deleted file mode 100644 index 39d6aed2..00000000 --- a/src/Orb.Tests/Service/Invoices/InvoiceServiceTest.cs +++ /dev/null @@ -1,168 +0,0 @@ -using InvoiceCreateParamsProperties = Orb.Models.Invoices.InvoiceCreateParamsProperties; -using InvoiceListParamsProperties = Orb.Models.Invoices.InvoiceListParamsProperties; -using Invoices = Orb.Models.Invoices; -using LineItemProperties = Orb.Models.Invoices.InvoiceCreateParamsProperties.LineItemProperties; -using Models = Orb.Models; -using PercentageDiscountProperties = Orb.Models.PercentageDiscountProperties; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TransformPriceFilterProperties = Orb.Models.TransformPriceFilterProperties; - -namespace Orb.Tests.Service.Invoices; - -public class InvoiceServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var invoice = await this.client.Invoices.Create( - new Invoices::InvoiceCreateParams() - { - Currency = "USD", - InvoiceDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - LineItems = - [ - new InvoiceCreateParamsProperties::LineItem() - { - EndDate = System::DateOnly.Parse("2023-09-22"), - ItemID = "4khy3nwzktxv7", - ModelType = LineItemProperties::ModelType.Unit, - Name = "Line Item Name", - Quantity = 1, - StartDate = System::DateOnly.Parse("2023-09-22"), - UnitConfig = new Models::UnitConfig() { UnitAmount = "unit_amount" }, - }, - ], - NetTerms = 0, - CustomerID = "4khy3nwzktxv7", - Discount = Models::Discount.Create( - new Models::PercentageDiscount() - { - DiscountType = PercentageDiscountProperties::DiscountType.Percentage, - PercentageDiscount1 = 0.15, - AppliesToPriceIDs = ["h74gfhdjvn7ujokd", "7hfgtgjnbvc3ujkl"], - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - Reason = "reason", - } - ), - ExternalCustomerID = "external-customer-id", - Memo = "An optional memo for my invoice.", - Metadata = new() { { "foo", "string" } }, - WillAutoIssue = false, - } - ); - invoice.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var invoice = await this.client.Invoices.Update( - new Invoices::InvoiceUpdateParams() - { - InvoiceID = "invoice_id", - Metadata = new() { { "foo", "string" } }, - } - ); - invoice.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Invoices.List( - new Invoices::InvoiceListParams() - { - Amount = "amount", - AmountGt = "amount[gt]", - AmountLt = "amount[lt]", - Cursor = "cursor", - CustomerID = "customer_id", - DateType = InvoiceListParamsProperties::DateType.DueDate, - DueDate = System::DateOnly.Parse("2019-12-27"), - DueDateWindow = "due_date_window", - DueDateGt = System::DateOnly.Parse("2019-12-27"), - DueDateLt = System::DateOnly.Parse("2019-12-27"), - ExternalCustomerID = "external_customer_id", - InvoiceDateGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - InvoiceDateGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - InvoiceDateLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - InvoiceDateLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - IsRecurring = true, - Limit = 1, - Status = [InvoiceListParamsProperties::Status.Draft], - SubscriptionID = "subscription_id", - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var invoice = await this.client.Invoices.Fetch( - new Invoices::InvoiceFetchParams() { InvoiceID = "invoice_id" } - ); - invoice.Validate(); - } - - [Fact] - public async Tasks::Task FetchUpcoming_Works() - { - var response = await this.client.Invoices.FetchUpcoming( - new Invoices::InvoiceFetchUpcomingParams() { SubscriptionID = "subscription_id" } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Issue_Works() - { - var invoice = await this.client.Invoices.Issue( - new Invoices::InvoiceIssueParams() { InvoiceID = "invoice_id", Synchronous = true } - ); - invoice.Validate(); - } - - [Fact] - public async Tasks::Task MarkPaid_Works() - { - var invoice = await this.client.Invoices.MarkPaid( - new Invoices::InvoiceMarkPaidParams() - { - InvoiceID = "invoice_id", - PaymentReceivedDate = System::DateOnly.Parse("2023-09-22"), - ExternalID = "external_payment_id_123", - Notes = "notes", - } - ); - invoice.Validate(); - } - - [Fact] - public async Tasks::Task Pay_Works() - { - var invoice = await this.client.Invoices.Pay( - new Invoices::InvoicePayParams() { InvoiceID = "invoice_id" } - ); - invoice.Validate(); - } - - [Fact] - public async Tasks::Task Void_Works() - { - var invoice = await this.client.Invoices.Void( - new Invoices::InvoiceVoidParams() { InvoiceID = "invoice_id" } - ); - invoice.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Items/ItemServiceTest.cs b/src/Orb.Tests/Service/Items/ItemServiceTest.cs deleted file mode 100644 index 527042b1..00000000 --- a/src/Orb.Tests/Service/Items/ItemServiceTest.cs +++ /dev/null @@ -1,73 +0,0 @@ -using ExternalConnectionProperties = Orb.Models.Items.ItemUpdateParamsProperties.ExternalConnectionProperties; -using Items = Orb.Models.Items; -using ItemUpdateParamsProperties = Orb.Models.Items.ItemUpdateParamsProperties; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Items; - -public class ItemServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var item = await this.client.Items.Create( - new Items::ItemCreateParams() - { - Name = "API requests", - Metadata = new() { { "foo", "string" } }, - } - ); - item.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var item = await this.client.Items.Update( - new Items::ItemUpdateParams() - { - ItemID = "item_id", - ExternalConnections = - [ - new ItemUpdateParamsProperties::ExternalConnection() - { - ExternalConnectionName = - ExternalConnectionProperties::ExternalConnectionName.Stripe, - ExternalEntityID = "external_entity_id", - }, - ], - Metadata = new() { { "foo", "string" } }, - Name = "name", - } - ); - item.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Items.List( - new Items::ItemListParams() { Cursor = "cursor", Limit = 1 } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Archive_Works() - { - var item = await this.client.Items.Archive( - new Items::ItemArchiveParams() { ItemID = "item_id" } - ); - item.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var item = await this.client.Items.Fetch( - new Items::ItemFetchParams() { ItemID = "item_id" } - ); - item.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Metrics/MetricServiceTest.cs b/src/Orb.Tests/Service/Metrics/MetricServiceTest.cs deleted file mode 100644 index 03ecd3e8..00000000 --- a/src/Orb.Tests/Service/Metrics/MetricServiceTest.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Metrics = Orb.Models.Metrics; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Metrics; - -public class MetricServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var billableMetric = await this.client.Metrics.Create( - new Metrics::MetricCreateParams() - { - Description = "Sum of bytes downloaded in fast mode", - ItemID = "item_id", - Name = "Bytes downloaded", - Sql = "SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", - Metadata = new() { { "foo", "string" } }, - } - ); - billableMetric.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var billableMetric = await this.client.Metrics.Update( - new Metrics::MetricUpdateParams() - { - MetricID = "metric_id", - Metadata = new() { { "foo", "string" } }, - } - ); - billableMetric.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Metrics.List( - new Metrics::MetricListParams() - { - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - Limit = 1, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var billableMetric = await this.client.Metrics.Fetch( - new Metrics::MetricFetchParams() { MetricID = "metric_id" } - ); - billableMetric.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Plans/ExternalPlanID/ExternalPlanIDServiceTest.cs b/src/Orb.Tests/Service/Plans/ExternalPlanID/ExternalPlanIDServiceTest.cs deleted file mode 100644 index 8db96387..00000000 --- a/src/Orb.Tests/Service/Plans/ExternalPlanID/ExternalPlanIDServiceTest.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ExternalPlanID = Orb.Models.Plans.ExternalPlanID; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Plans.ExternalPlanID; - -public class ExternalPlanIDServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Update_Works() - { - var plan = await this.client.Plans.ExternalPlanID.Update( - new ExternalPlanID::ExternalPlanIDUpdateParams() - { - OtherExternalPlanID = "external_plan_id", - ExternalPlanID = "external_plan_id", - Metadata = new() { { "foo", "string" } }, - } - ); - plan.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var plan = await this.client.Plans.ExternalPlanID.Fetch( - new ExternalPlanID::ExternalPlanIDFetchParams() { ExternalPlanID = "external_plan_id" } - ); - plan.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Plans/PlanServiceTest.cs b/src/Orb.Tests/Service/Plans/PlanServiceTest.cs deleted file mode 100644 index 88311583..00000000 --- a/src/Orb.Tests/Service/Plans/PlanServiceTest.cs +++ /dev/null @@ -1,197 +0,0 @@ -using AdjustmentProperties = Orb.Models.Plans.PlanCreateParamsProperties.AdjustmentProperties; -using CustomExpirationProperties = Orb.Models.CustomExpirationProperties; -using Models = Orb.Models; -using NewAllocationPriceProperties = Orb.Models.NewAllocationPriceProperties; -using NewBillingCycleConfigurationProperties = Orb.Models.NewBillingCycleConfigurationProperties; -using NewPercentageDiscountProperties = Orb.Models.NewPercentageDiscountProperties; -using NewPlanUnitPriceProperties = Orb.Models.NewPlanUnitPriceProperties; -using PlanCreateParamsProperties = Orb.Models.Plans.PlanCreateParamsProperties; -using PlanListParamsProperties = Orb.Models.Plans.PlanListParamsProperties; -using PlanPhaseProperties = Orb.Models.Plans.PlanCreateParamsProperties.PlanPhaseProperties; -using Plans = Orb.Models.Plans; -using PriceProperties = Orb.Models.Plans.PlanCreateParamsProperties.PriceProperties; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TransformPriceFilterProperties = Orb.Models.TransformPriceFilterProperties; -using UnitConversionRateConfigProperties = Orb.Models.UnitConversionRateConfigProperties; - -namespace Orb.Tests.Service.Plans; - -public class PlanServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var plan = await this.client.Plans.Create( - new Plans::PlanCreateParams() - { - Currency = "currency", - Name = "name", - Prices = - [ - new PlanCreateParamsProperties::Price() - { - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - PlanPhaseOrder = 0, - Price1 = PriceProperties::Price.Create( - new Models::NewPlanUnitPrice() - { - Cadence = NewPlanUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewPlanUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewPlanUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - }, - ], - Adjustments = - [ - new PlanCreateParamsProperties::Adjustment() - { - Adjustment1 = AdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - PlanPhaseOrder = 0, - }, - ], - DefaultInvoiceMemo = "default_invoice_memo", - ExternalPlanID = "external_plan_id", - Metadata = new() { { "foo", "string" } }, - NetTerms = 0, - PlanPhases = - [ - new PlanCreateParamsProperties::PlanPhase() - { - Order = 0, - AlignBillingWithPhaseStartDate = true, - Duration = 1, - DurationUnit = PlanPhaseProperties::DurationUnit.Daily, - }, - ], - Status = PlanCreateParamsProperties::Status.Active, - } - ); - plan.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var plan = await this.client.Plans.Update( - new Plans::PlanUpdateParams() - { - PlanID = "plan_id", - ExternalPlanID = "external_plan_id", - Metadata = new() { { "foo", "string" } }, - } - ); - plan.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Plans.List( - new Plans::PlanListParams() - { - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - Limit = 1, - Status = PlanListParamsProperties::Status.Active, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var plan = await this.client.Plans.Fetch( - new Plans::PlanFetchParams() { PlanID = "plan_id" } - ); - plan.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Prices/ExternalPriceID/ExternalPriceIDServiceTest.cs b/src/Orb.Tests/Service/Prices/ExternalPriceID/ExternalPriceIDServiceTest.cs deleted file mode 100644 index a4a05f58..00000000 --- a/src/Orb.Tests/Service/Prices/ExternalPriceID/ExternalPriceIDServiceTest.cs +++ /dev/null @@ -1,33 +0,0 @@ -using ExternalPriceID = Orb.Models.Prices.ExternalPriceID; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.Prices.ExternalPriceID; - -public class ExternalPriceIDServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Update_Works() - { - var price = await this.client.Prices.ExternalPriceID.Update( - new ExternalPriceID::ExternalPriceIDUpdateParams() - { - ExternalPriceID = "external_price_id", - Metadata = new() { { "foo", "string" } }, - } - ); - price.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var price = await this.client.Prices.ExternalPriceID.Fetch( - new ExternalPriceID::ExternalPriceIDFetchParams() - { - ExternalPriceID = "external_price_id", - } - ); - price.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Prices/PriceServiceTest.cs b/src/Orb.Tests/Service/Prices/PriceServiceTest.cs deleted file mode 100644 index 2ea6f903..00000000 --- a/src/Orb.Tests/Service/Prices/PriceServiceTest.cs +++ /dev/null @@ -1,301 +0,0 @@ -using Json = System.Text.Json; -using Models = Orb.Models; -using NewBillingCycleConfigurationProperties = Orb.Models.NewBillingCycleConfigurationProperties; -using NewFloatingUnitPriceProperties = Orb.Models.NewFloatingUnitPriceProperties; -using PriceCreateParamsProperties = Orb.Models.Prices.PriceCreateParamsProperties; -using PriceEvaluateMultipleParamsProperties = Orb.Models.Prices.PriceEvaluateMultipleParamsProperties; -using PriceEvaluatePreviewEventsParamsProperties = Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties; -using PriceEvaluationProperties = Orb.Models.Prices.PriceEvaluateMultipleParamsProperties.PriceEvaluationProperties; -using PriceEvaluationProperties1 = Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties.PriceEvaluationProperties; -using Prices = Orb.Models.Prices; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using UnitConversionRateConfigProperties = Orb.Models.UnitConversionRateConfigProperties; - -namespace Orb.Tests.Service.Prices; - -public class PriceServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var price = await this.client.Prices.Create( - new Prices::PriceCreateParams() - { - Body = PriceCreateParamsProperties::Body.Create( - new Models::NewFloatingUnitPrice() - { - Cadence = NewFloatingUnitPriceProperties::Cadence.Annual, - Currency = "currency", - ItemID = "item_id", - ModelType = NewFloatingUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() { UnitAmount = "unit_amount" }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewFloatingUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - } - ), - } - ); - price.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var price = await this.client.Prices.Update( - new Prices::PriceUpdateParams() - { - PriceID = "price_id", - Metadata = new() { { "foo", "string" } }, - } - ); - price.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Prices.List( - new Prices::PriceListParams() { Cursor = "cursor", Limit = 1 } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Evaluate_Works() - { - var response = await this.client.Prices.Evaluate( - new Prices::PriceEvaluateParams() - { - PriceID = "price_id", - TimeframeEnd = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - TimeframeStart = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CustomerID = "customer_id", - ExternalCustomerID = "external_customer_id", - Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", - GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task EvaluateMultiple_Works() - { - var response = await this.client.Prices.EvaluateMultiple( - new Prices::PriceEvaluateMultipleParams() - { - TimeframeEnd = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - TimeframeStart = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CustomerID = "customer_id", - ExternalCustomerID = "external_customer_id", - PriceEvaluations = - [ - new PriceEvaluateMultipleParamsProperties::PriceEvaluation() - { - ExternalPriceID = "external_price_id", - Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", - GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], - Price = PriceEvaluationProperties::Price.Create( - new Models::NewFloatingUnitPrice() - { - Cadence = NewFloatingUnitPriceProperties::Cadence.Annual, - Currency = "currency", - ItemID = "item_id", - ModelType = NewFloatingUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewFloatingUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - } - ), - PriceID = "price_id", - }, - ], - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task EvaluatePreviewEvents_Works() - { - var response = await this.client.Prices.EvaluatePreviewEvents( - new Prices::PriceEvaluatePreviewEventsParams() - { - TimeframeEnd = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - TimeframeStart = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CustomerID = "customer_id", - Events = - [ - new PriceEvaluatePreviewEventsParamsProperties::Event() - { - EventName = "event_name", - Properties1 = new() - { - { "foo", Json::JsonSerializer.SerializeToElement("bar") }, - }, - Timestamp = System::DateTime.Parse("2020-12-09T16:09:53Z"), - CustomerID = "customer_id", - ExternalCustomerID = "external_customer_id", - }, - ], - ExternalCustomerID = "external_customer_id", - PriceEvaluations = - [ - new PriceEvaluatePreviewEventsParamsProperties::PriceEvaluation() - { - ExternalPriceID = "external_price_id", - Filter = "my_numeric_property > 100 AND my_other_property = 'bar'", - GroupingKeys = ["case when my_event_type = 'foo' then true else false end"], - Price = PriceEvaluationProperties1::Price.Create( - new Models::NewFloatingUnitPrice() - { - Cadence = NewFloatingUnitPriceProperties::Cadence.Annual, - Currency = "currency", - ItemID = "item_id", - ModelType = NewFloatingUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewFloatingUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - } - ), - PriceID = "price_id", - }, - ], - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var price = await this.client.Prices.Fetch( - new Prices::PriceFetchParams() { PriceID = "price_id" } - ); - price.Validate(); - } -} diff --git a/src/Orb.Tests/Service/SubscriptionChanges/SubscriptionChangeServiceTest.cs b/src/Orb.Tests/Service/SubscriptionChanges/SubscriptionChangeServiceTest.cs deleted file mode 100644 index 25aed8e5..00000000 --- a/src/Orb.Tests/Service/SubscriptionChanges/SubscriptionChangeServiceTest.cs +++ /dev/null @@ -1,46 +0,0 @@ -using SubscriptionChanges = Orb.Models.SubscriptionChanges; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; - -namespace Orb.Tests.Service.SubscriptionChanges; - -public class SubscriptionChangeServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Retrieve_Works() - { - var subscriptionChange = await this.client.SubscriptionChanges.Retrieve( - new SubscriptionChanges::SubscriptionChangeRetrieveParams() - { - SubscriptionChangeID = "subscription_change_id", - } - ); - subscriptionChange.Validate(); - } - - [Fact] - public async Tasks::Task Apply_Works() - { - var response = await this.client.SubscriptionChanges.Apply( - new SubscriptionChanges::SubscriptionChangeApplyParams() - { - SubscriptionChangeID = "subscription_change_id", - Description = "description", - PreviouslyCollectedAmount = "previously_collected_amount", - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task Cancel_Works() - { - var response = await this.client.SubscriptionChanges.Cancel( - new SubscriptionChanges::SubscriptionChangeCancelParams() - { - SubscriptionChangeID = "subscription_change_id", - } - ); - response.Validate(); - } -} diff --git a/src/Orb.Tests/Service/Subscriptions/SubscriptionServiceTest.cs b/src/Orb.Tests/Service/Subscriptions/SubscriptionServiceTest.cs deleted file mode 100644 index 3c6dffc8..00000000 --- a/src/Orb.Tests/Service/Subscriptions/SubscriptionServiceTest.cs +++ /dev/null @@ -1,1056 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddAdjustmentProperties; -using AddAdjustmentProperties1 = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; -using AddAdjustmentProperties2 = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddAdjustmentProperties; -using AddPriceProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddPriceProperties; -using AddPriceProperties1 = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddPriceProperties; -using AddProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; -using AmountProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.AmountProperties; -using CustomExpirationProperties = Orb.Models.CustomExpirationProperties; -using DiscountOverrideProperties = Orb.Models.Subscriptions.DiscountOverrideProperties; -using DiscountProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties; -using EditAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties; -using EditProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewAllocationPriceProperties = Orb.Models.NewAllocationPriceProperties; -using NewBillingCycleConfigurationProperties = Orb.Models.NewBillingCycleConfigurationProperties; -using NewFloatingUnitPriceProperties = Orb.Models.NewFloatingUnitPriceProperties; -using NewPercentageDiscountProperties = Orb.Models.NewPercentageDiscountProperties; -using NewSubscriptionUnitPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties; -using ReplaceAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplaceAdjustmentProperties; -using ReplaceAdjustmentProperties1 = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplaceAdjustmentProperties; -using ReplacePriceProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplacePriceProperties; -using ReplacePriceProperties1 = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplacePriceProperties; -using SubscriptionCancelParamsProperties = Orb.Models.Subscriptions.SubscriptionCancelParamsProperties; -using SubscriptionCreateParamsProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; -using SubscriptionFetchCostsParamsProperties = Orb.Models.Subscriptions.SubscriptionFetchCostsParamsProperties; -using SubscriptionFetchUsageParamsProperties = Orb.Models.Subscriptions.SubscriptionFetchUsageParamsProperties; -using SubscriptionListParamsProperties = Orb.Models.Subscriptions.SubscriptionListParamsProperties; -using SubscriptionPriceIntervalsParamsProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties; -using SubscriptionRedeemCouponParamsProperties = Orb.Models.Subscriptions.SubscriptionRedeemCouponParamsProperties; -using Subscriptions = Orb.Models.Subscriptions; -using SubscriptionSchedulePlanChangeParamsProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; -using SubscriptionUpdateFixedFeeQuantityParamsProperties = Orb.Models.Subscriptions.SubscriptionUpdateFixedFeeQuantityParamsProperties; -using SubscriptionUpdateTrialParamsProperties = Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties; -using System = System; -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TransformPriceFilterProperties = Orb.Models.TransformPriceFilterProperties; -using UnitConversionRateConfigProperties = Orb.Models.UnitConversionRateConfigProperties; - -namespace Orb.Tests.Service.Subscriptions; - -public class SubscriptionServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Create_Works() - { - var mutatedSubscription = await this.client.Subscriptions.Create( - new Subscriptions::SubscriptionCreateParams() - { - AddAdjustments = - [ - new SubscriptionCreateParamsProperties::AddAdjustment() - { - Adjustment = AddAdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - EndDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - PlanPhaseOrder = 0, - StartDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - }, - ], - AddPrices = - [ - new SubscriptionCreateParamsProperties::AddPrice() - { - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - Discounts = - [ - new Subscriptions::DiscountOverride() - { - DiscountType = DiscountOverrideProperties::DiscountType.Percentage, - AmountDiscount = "amount_discount", - PercentageDiscount = 0.15, - UsageDiscount = 0, - }, - ], - EndDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExternalPriceID = "external_price_id", - MaximumAmount = "1.23", - MinimumAmount = "1.23", - PlanPhaseOrder = 0, - Price = AddPriceProperties::Price.Create( - new Subscriptions::NewSubscriptionUnitPrice() - { - Cadence = NewSubscriptionUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewSubscriptionUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewSubscriptionUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - PriceID = "h74gfhdjvn7ujokd", - StartDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - }, - ], - AlignBillingWithSubscriptionStartDate = true, - AutoCollection = true, - AwsRegion = "aws_region", - BillingCycleAnchorConfiguration = new Models::BillingCycleAnchorConfiguration() - { - Day = 1, - Month = 1, - Year = 0, - }, - CouponRedemptionCode = "coupon_redemption_code", - CreditsOverageRate = 0, - Currency = "currency", - CustomerID = "customer_id", - DefaultInvoiceMemo = "default_invoice_memo", - EndDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExternalCustomerID = "external_customer_id", - ExternalMarketplace = - SubscriptionCreateParamsProperties::ExternalMarketplace.Google, - ExternalMarketplaceReportingID = "external_marketplace_reporting_id", - ExternalPlanID = "ZMwNQefe7J3ecf7W", - Filter = "my_property > 100 AND my_other_property = 'bar'", - InitialPhaseOrder = 2, - InvoicingThreshold = "10.00", - Metadata = new() { { "foo", "string" } }, - Name = "name", - NetTerms = 0, - PerCreditOverageAmount = 0, - PlanID = "ZMwNQefe7J3ecf7W", - PlanVersionNumber = 0, - PriceOverrides = [Json::JsonSerializer.Deserialize("{}")], - RemoveAdjustments = - [ - new SubscriptionCreateParamsProperties::RemoveAdjustment() - { - AdjustmentID = "h74gfhdjvn7ujokd", - }, - ], - RemovePrices = - [ - new SubscriptionCreateParamsProperties::RemovePrice() - { - ExternalPriceID = "external_price_id", - PriceID = "h74gfhdjvn7ujokd", - }, - ], - ReplaceAdjustments = - [ - new SubscriptionCreateParamsProperties::ReplaceAdjustment() - { - Adjustment = ReplaceAdjustmentProperties::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - ReplacesAdjustmentID = "replaces_adjustment_id", - }, - ], - ReplacePrices = - [ - new SubscriptionCreateParamsProperties::ReplacePrice() - { - ReplacesPriceID = "replaces_price_id", - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - Discounts = - [ - new Subscriptions::DiscountOverride() - { - DiscountType = DiscountOverrideProperties::DiscountType.Percentage, - AmountDiscount = "amount_discount", - PercentageDiscount = 0.15, - UsageDiscount = 0, - }, - ], - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 2, - MaximumAmount = "1.23", - MinimumAmount = "1.23", - Price = ReplacePriceProperties::Price.Create( - new Subscriptions::NewSubscriptionUnitPrice() - { - Cadence = NewSubscriptionUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewSubscriptionUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewSubscriptionUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - PriceID = "h74gfhdjvn7ujokd", - }, - ], - StartDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - TrialDurationDays = 0, - UsageCustomerIDs = ["string"], - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task Update_Works() - { - var subscription = await this.client.Subscriptions.Update( - new Subscriptions::SubscriptionUpdateParams() - { - SubscriptionID = "subscription_id", - AutoCollection = true, - DefaultInvoiceMemo = "default_invoice_memo", - InvoicingThreshold = "10.00", - Metadata = new() { { "foo", "string" } }, - NetTerms = 0, - } - ); - subscription.Validate(); - } - - [Fact] - public async Tasks::Task List_Works() - { - var page = await this.client.Subscriptions.List( - new Subscriptions::SubscriptionListParams() - { - CreatedAtGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - CreatedAtLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Cursor = "cursor", - CustomerID = ["string"], - ExternalCustomerID = ["string"], - Limit = 1, - Status = SubscriptionListParamsProperties::Status.Active, - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task Cancel_Works() - { - var mutatedSubscription = await this.client.Subscriptions.Cancel( - new Subscriptions::SubscriptionCancelParams() - { - SubscriptionID = "subscription_id", - CancelOption = - SubscriptionCancelParamsProperties::CancelOption.EndOfSubscriptionTerm, - AllowInvoiceCreditOrVoid = true, - CancellationDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task Fetch_Works() - { - var subscription = await this.client.Subscriptions.Fetch( - new Subscriptions::SubscriptionFetchParams() { SubscriptionID = "subscription_id" } - ); - subscription.Validate(); - } - - [Fact] - public async Tasks::Task FetchCosts_Works() - { - var response = await this.client.Subscriptions.FetchCosts( - new Subscriptions::SubscriptionFetchCostsParams() - { - SubscriptionID = "subscription_id", - Currency = "currency", - TimeframeEnd = System::DateTime.Parse("2022-03-01T05:00:00Z"), - TimeframeStart = System::DateTime.Parse("2022-02-01T05:00:00Z"), - ViewMode = SubscriptionFetchCostsParamsProperties::ViewMode.Periodic, - } - ); - response.Validate(); - } - - [Fact] - public async Tasks::Task FetchSchedule_Works() - { - var page = await this.client.Subscriptions.FetchSchedule( - new Subscriptions::SubscriptionFetchScheduleParams() - { - SubscriptionID = "subscription_id", - Cursor = "cursor", - Limit = 1, - StartDateGt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - StartDateGte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - StartDateLt = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - StartDateLte = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - } - ); - page.Validate(); - } - - [Fact] - public async Tasks::Task FetchUsage_Works() - { - var subscriptionUsage = await this.client.Subscriptions.FetchUsage( - new Subscriptions::SubscriptionFetchUsageParams() - { - SubscriptionID = "subscription_id", - BillableMetricID = "billable_metric_id", - FirstDimensionKey = "first_dimension_key", - FirstDimensionValue = "first_dimension_value", - Granularity = SubscriptionFetchUsageParamsProperties::Granularity.Day, - GroupBy = "group_by", - SecondDimensionKey = "second_dimension_key", - SecondDimensionValue = "second_dimension_value", - TimeframeEnd = System::DateTime.Parse("2022-03-01T05:00:00Z"), - TimeframeStart = System::DateTime.Parse("2022-02-01T05:00:00Z"), - ViewMode = SubscriptionFetchUsageParamsProperties::ViewMode.Periodic, - } - ); - subscriptionUsage.Validate(); - } - - [Fact] - public async Tasks::Task PriceIntervals_Works() - { - var mutatedSubscription = await this.client.Subscriptions.PriceIntervals( - new Subscriptions::SubscriptionPriceIntervalsParams() - { - SubscriptionID = "subscription_id", - Add = - [ - new SubscriptionPriceIntervalsParamsProperties::Add() - { - StartDate = AddProperties::StartDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - Discounts = - [ - AddProperties::Discount.Create( - new DiscountProperties::Amount() - { - AmountDiscount = 0, - DiscountType = AmountProperties::DiscountType.Amount, - } - ), - ], - EndDate = AddProperties::EndDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - ExternalPriceID = "external_price_id", - Filter = "my_property > 100 AND my_other_property = 'bar'", - FixedFeeQuantityTransitions = - [ - new AddProperties::FixedFeeQuantityTransition() - { - EffectiveDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Quantity = 5, - }, - ], - MaximumAmount = 0, - MinimumAmount = 0, - Price = AddProperties::Price.Create( - new Models::NewFloatingUnitPrice() - { - Cadence = NewFloatingUnitPriceProperties::Cadence.Annual, - Currency = "currency", - ItemID = "item_id", - ModelType = NewFloatingUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewFloatingUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - } - ), - PriceID = "h74gfhdjvn7ujokd", - UsageCustomerIDs = ["string"], - }, - ], - AddAdjustments = - [ - new SubscriptionPriceIntervalsParamsProperties::AddAdjustment() - { - Adjustment = AddAdjustmentProperties1::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - StartDate = AddAdjustmentProperties1::StartDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - EndDate = AddAdjustmentProperties1::EndDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - }, - ], - AllowInvoiceCreditOrVoid = true, - Edit = - [ - new SubscriptionPriceIntervalsParamsProperties::Edit() - { - PriceIntervalID = "sdfs6wdjvn7ujokd", - BillingCycleDay = 0, - EndDate = EditProperties::EndDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - Filter = "my_property > 100 AND my_other_property = 'bar'", - FixedFeeQuantityTransitions = - [ - new EditProperties::FixedFeeQuantityTransition() - { - EffectiveDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - Quantity = 5, - }, - ], - StartDate = EditProperties::StartDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - UsageCustomerIDs = ["string"], - }, - ], - EditAdjustments = - [ - new SubscriptionPriceIntervalsParamsProperties::EditAdjustment() - { - AdjustmentIntervalID = "sdfs6wdjvn7ujokd", - EndDate = EditAdjustmentProperties::EndDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - StartDate = EditAdjustmentProperties::StartDate.Create( - System::DateTime.Parse("2019-12-27T18:11:19.117Z") - ), - }, - ], - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task RedeemCoupon_Works() - { - var mutatedSubscription = await this.client.Subscriptions.RedeemCoupon( - new Subscriptions::SubscriptionRedeemCouponParams() - { - SubscriptionID = "subscription_id", - ChangeOption = SubscriptionRedeemCouponParamsProperties::ChangeOption.RequestedDate, - AllowInvoiceCreditOrVoid = true, - ChangeDate = System::DateTime.Parse("2017-07-21T17:32:28Z"), - CouponID = "coupon_id", - CouponRedemptionCode = "coupon_redemption_code", - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task SchedulePlanChange_Works() - { - var mutatedSubscription = await this.client.Subscriptions.SchedulePlanChange( - new Subscriptions::SubscriptionSchedulePlanChangeParams() - { - SubscriptionID = "subscription_id", - ChangeOption = - SubscriptionSchedulePlanChangeParamsProperties::ChangeOption.RequestedDate, - AddAdjustments = - [ - new SubscriptionSchedulePlanChangeParamsProperties::AddAdjustment() - { - Adjustment = AddAdjustmentProperties2::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - EndDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - PlanPhaseOrder = 0, - StartDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - }, - ], - AddPrices = - [ - new SubscriptionSchedulePlanChangeParamsProperties::AddPrice() - { - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - Discounts = - [ - new Subscriptions::DiscountOverride() - { - DiscountType = DiscountOverrideProperties::DiscountType.Percentage, - AmountDiscount = "amount_discount", - PercentageDiscount = 0.15, - UsageDiscount = 0, - }, - ], - EndDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - ExternalPriceID = "external_price_id", - MaximumAmount = "1.23", - MinimumAmount = "1.23", - PlanPhaseOrder = 0, - Price = AddPriceProperties1::Price.Create( - new Subscriptions::NewSubscriptionUnitPrice() - { - Cadence = NewSubscriptionUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewSubscriptionUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewSubscriptionUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - PriceID = "h74gfhdjvn7ujokd", - StartDate = System::DateTime.Parse("2019-12-27T18:11:19.117Z"), - }, - ], - AlignBillingWithPlanChangeDate = true, - AutoCollection = true, - BillingCycleAlignment = - SubscriptionSchedulePlanChangeParamsProperties::BillingCycleAlignment.Unchanged, - BillingCycleAnchorConfiguration = new Models::BillingCycleAnchorConfiguration() - { - Day = 1, - Month = 1, - Year = 0, - }, - ChangeDate = System::DateTime.Parse("2017-07-21T17:32:28Z"), - CouponRedemptionCode = "coupon_redemption_code", - CreditsOverageRate = 0, - DefaultInvoiceMemo = "default_invoice_memo", - ExternalPlanID = "ZMwNQefe7J3ecf7W", - Filter = "my_property > 100 AND my_other_property = 'bar'", - InitialPhaseOrder = 2, - InvoicingThreshold = "10.00", - NetTerms = 0, - PerCreditOverageAmount = 0, - PlanID = "ZMwNQefe7J3ecf7W", - PlanVersionNumber = 0, - PriceOverrides = [Json::JsonSerializer.Deserialize("{}")], - RemoveAdjustments = - [ - new SubscriptionSchedulePlanChangeParamsProperties::RemoveAdjustment() - { - AdjustmentID = "h74gfhdjvn7ujokd", - }, - ], - RemovePrices = - [ - new SubscriptionSchedulePlanChangeParamsProperties::RemovePrice() - { - ExternalPriceID = "external_price_id", - PriceID = "h74gfhdjvn7ujokd", - }, - ], - ReplaceAdjustments = - [ - new SubscriptionSchedulePlanChangeParamsProperties::ReplaceAdjustment() - { - Adjustment = ReplaceAdjustmentProperties1::Adjustment.Create( - new Models::NewPercentageDiscount() - { - AdjustmentType = - NewPercentageDiscountProperties::AdjustmentType.PercentageDiscount, - PercentageDiscount = 0, - AppliesToAll = NewPercentageDiscountProperties::AppliesToAll.True, - AppliesToItemIDs = ["item_1", "item_2"], - AppliesToPriceIDs = ["price_1", "price_2"], - Currency = "currency", - Filters = - [ - new Models::TransformPriceFilter() - { - Field = TransformPriceFilterProperties::Field.PriceID, - Operator = - TransformPriceFilterProperties::Operator.Includes, - Values = ["string"], - }, - ], - IsInvoiceLevel = true, - PriceType = NewPercentageDiscountProperties::PriceType.Usage, - } - ), - ReplacesAdjustmentID = "replaces_adjustment_id", - }, - ], - ReplacePrices = - [ - new SubscriptionSchedulePlanChangeParamsProperties::ReplacePrice() - { - ReplacesPriceID = "replaces_price_id", - AllocationPrice = new Models::NewAllocationPrice() - { - Amount = "10.00", - Cadence = NewAllocationPriceProperties::Cadence.Monthly, - Currency = "USD", - CustomExpiration = new Models::CustomExpiration() - { - Duration = 0, - DurationUnit = CustomExpirationProperties::DurationUnit.Day, - }, - ExpiresAtEndOfCadence = true, - }, - Discounts = - [ - new Subscriptions::DiscountOverride() - { - DiscountType = DiscountOverrideProperties::DiscountType.Percentage, - AmountDiscount = "amount_discount", - PercentageDiscount = 0.15, - UsageDiscount = 0, - }, - ], - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 2, - MaximumAmount = "1.23", - MinimumAmount = "1.23", - Price = ReplacePriceProperties1::Price.Create( - new Subscriptions::NewSubscriptionUnitPrice() - { - Cadence = NewSubscriptionUnitPriceProperties::Cadence.Annual, - ItemID = "item_id", - ModelType = NewSubscriptionUnitPriceProperties::ModelType.Unit, - Name = "Annual fee", - UnitConfig = new Models::UnitConfig() - { - UnitAmount = "unit_amount", - }, - BillableMetricID = "billable_metric_id", - BilledInAdvance = true, - BillingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - ConversionRate = 0, - ConversionRateConfig = - NewSubscriptionUnitPriceProperties::ConversionRateConfig.Create( - new Models::UnitConversionRateConfig() - { - ConversionRateType = - UnitConversionRateConfigProperties::ConversionRateType.Unit, - UnitConfig = new Models::ConversionRateUnitConfig() - { - UnitAmount = "unit_amount", - }, - } - ), - Currency = "currency", - DimensionalPriceConfiguration = - new Models::NewDimensionalPriceConfiguration() - { - DimensionValues = ["string"], - DimensionalPriceGroupID = "dimensional_price_group_id", - ExternalDimensionalPriceGroupID = - "external_dimensional_price_group_id", - }, - ExternalPriceID = "external_price_id", - FixedPriceQuantity = 0, - InvoiceGroupingKey = "x", - InvoicingCycleConfiguration = - new Models::NewBillingCycleConfiguration() - { - Duration = 0, - DurationUnit = - NewBillingCycleConfigurationProperties::DurationUnit.Day, - }, - Metadata = new() { { "foo", "string" } }, - ReferenceID = "reference_id", - } - ), - PriceID = "h74gfhdjvn7ujokd", - }, - ], - TrialDurationDays = 0, - UsageCustomerIDs = ["string"], - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task TriggerPhase_Works() - { - var mutatedSubscription = await this.client.Subscriptions.TriggerPhase( - new Subscriptions::SubscriptionTriggerPhaseParams() - { - SubscriptionID = "subscription_id", - AllowInvoiceCreditOrVoid = true, - EffectiveDate = System::DateOnly.Parse("2019-12-27"), - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task UnscheduleCancellation_Works() - { - var mutatedSubscription = await this.client.Subscriptions.UnscheduleCancellation( - new Subscriptions::SubscriptionUnscheduleCancellationParams() - { - SubscriptionID = "subscription_id", - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task UnscheduleFixedFeeQuantityUpdates_Works() - { - var mutatedSubscription = await this.client.Subscriptions.UnscheduleFixedFeeQuantityUpdates( - new Subscriptions::SubscriptionUnscheduleFixedFeeQuantityUpdatesParams() - { - SubscriptionID = "subscription_id", - PriceID = "price_id", - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task UnschedulePendingPlanChanges_Works() - { - var mutatedSubscription = await this.client.Subscriptions.UnschedulePendingPlanChanges( - new Subscriptions::SubscriptionUnschedulePendingPlanChangesParams() - { - SubscriptionID = "subscription_id", - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task UpdateFixedFeeQuantity_Works() - { - var mutatedSubscription = await this.client.Subscriptions.UpdateFixedFeeQuantity( - new Subscriptions::SubscriptionUpdateFixedFeeQuantityParams() - { - SubscriptionID = "subscription_id", - PriceID = "price_id", - Quantity = 0, - AllowInvoiceCreditOrVoid = true, - ChangeOption = - SubscriptionUpdateFixedFeeQuantityParamsProperties::ChangeOption.Immediate, - EffectiveDate = System::DateOnly.Parse("2022-12-21"), - } - ); - mutatedSubscription.Validate(); - } - - [Fact] - public async Tasks::Task UpdateTrial_Works() - { - var mutatedSubscription = await this.client.Subscriptions.UpdateTrial( - new Subscriptions::SubscriptionUpdateTrialParams() - { - SubscriptionID = "subscription_id", - TrialEndDate = SubscriptionUpdateTrialParamsProperties::TrialEndDate.Create( - System::DateTime.Parse("2017-07-21T17:32:28Z") - ), - Shift = true, - } - ); - mutatedSubscription.Validate(); - } -} diff --git a/src/Orb.Tests/Service/TopLevel/TopLevelServiceTest.cs b/src/Orb.Tests/Service/TopLevel/TopLevelServiceTest.cs deleted file mode 100644 index 74d84075..00000000 --- a/src/Orb.Tests/Service/TopLevel/TopLevelServiceTest.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Tasks = System.Threading.Tasks; -using Tests = Orb.Tests; -using TopLevel = Orb.Models.TopLevel; - -namespace Orb.Tests.Service.TopLevel; - -public class TopLevelServiceTest : Tests::TestBase -{ - [Fact] - public async Tasks::Task Ping_Works() - { - var response = await this.client.TopLevel.Ping(new TopLevel::TopLevelPingParams() { }); - response.Validate(); - } -} diff --git a/src/Orb.Tests/Services/AlertServiceTest.cs b/src/Orb.Tests/Services/AlertServiceTest.cs new file mode 100644 index 00000000..bcd23603 --- /dev/null +++ b/src/Orb.Tests/Services/AlertServiceTest.cs @@ -0,0 +1,99 @@ +using System.Threading.Tasks; +using Orb.Models.Alerts; + +namespace Orb.Tests.Services; + +public class AlertServiceTest : TestBase +{ + [Fact] + public async Task Retrieve_Works() + { + var alert = await this.client.Alerts.Retrieve( + "alert_id", + new(), + TestContext.Current.CancellationToken + ); + alert.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var alert = await this.client.Alerts.Update( + "alert_configuration_id", + new() { Thresholds = [new(0)] }, + TestContext.Current.CancellationToken + ); + alert.Validate(); + } + + [Fact(Skip = "plan_version=0 breaks Prism")] + public async Task List_Works() + { + var page = await this.client.Alerts.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task CreateForCustomer_Works() + { + var alert = await this.client.Alerts.CreateForCustomer( + "customer_id", + new() { Currency = "currency", Type = Type.CreditBalanceDepleted }, + TestContext.Current.CancellationToken + ); + alert.Validate(); + } + + [Fact] + public async Task CreateForExternalCustomer_Works() + { + var alert = await this.client.Alerts.CreateForExternalCustomer( + "external_customer_id", + new() + { + Currency = "currency", + Type = AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted, + }, + TestContext.Current.CancellationToken + ); + alert.Validate(); + } + + [Fact] + public async Task CreateForSubscription_Works() + { + var alert = await this.client.Alerts.CreateForSubscription( + "subscription_id", + new() + { + Thresholds = [new(0)], + Type = AlertCreateForSubscriptionParamsType.UsageExceeded, + }, + TestContext.Current.CancellationToken + ); + alert.Validate(); + } + + [Fact] + public async Task Disable_Works() + { + var alert = await this.client.Alerts.Disable( + "alert_configuration_id", + new(), + TestContext.Current.CancellationToken + ); + alert.Validate(); + } + + [Fact] + public async Task Enable_Works() + { + var alert = await this.client.Alerts.Enable( + "alert_configuration_id", + new(), + TestContext.Current.CancellationToken + ); + alert.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Beta/ExternalPlanIDServiceTest.cs b/src/Orb.Tests/Services/Beta/ExternalPlanIDServiceTest.cs new file mode 100644 index 00000000..628de8fd --- /dev/null +++ b/src/Orb.Tests/Services/Beta/ExternalPlanIDServiceTest.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Beta; + +public class ExternalPlanIDServiceTest : TestBase +{ + [Fact] + public async Task CreatePlanVersion_Works() + { + var planVersion = await this.client.Beta.ExternalPlanID.CreatePlanVersion( + "external_plan_id", + new() { Version = 0 }, + TestContext.Current.CancellationToken + ); + planVersion.Validate(); + } + + [Fact] + public async Task FetchPlanVersion_Works() + { + var planVersion = await this.client.Beta.ExternalPlanID.FetchPlanVersion( + "version", + new() { ExternalPlanID = "external_plan_id" }, + TestContext.Current.CancellationToken + ); + planVersion.Validate(); + } + + [Fact] + public async Task SetDefaultPlanVersion_Works() + { + var plan = await this.client.Beta.ExternalPlanID.SetDefaultPlanVersion( + "external_plan_id", + new() { Version = 0 }, + TestContext.Current.CancellationToken + ); + plan.Validate(); + } +} diff --git a/src/Orb.Tests/Services/BetaServiceTest.cs b/src/Orb.Tests/Services/BetaServiceTest.cs new file mode 100644 index 00000000..9b7e038b --- /dev/null +++ b/src/Orb.Tests/Services/BetaServiceTest.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class BetaServiceTest : TestBase +{ + [Fact] + public async Task CreatePlanVersion_Works() + { + var planVersion = await this.client.Beta.CreatePlanVersion( + "plan_id", + new() { Version = 0 }, + TestContext.Current.CancellationToken + ); + planVersion.Validate(); + } + + [Fact] + public async Task FetchPlanVersion_Works() + { + var planVersion = await this.client.Beta.FetchPlanVersion( + "version", + new() { PlanID = "plan_id" }, + TestContext.Current.CancellationToken + ); + planVersion.Validate(); + } + + [Fact] + public async Task SetDefaultPlanVersion_Works() + { + var plan = await this.client.Beta.SetDefaultPlanVersion( + "plan_id", + new() { Version = 0 }, + TestContext.Current.CancellationToken + ); + plan.Validate(); + } +} diff --git a/src/Orb.Tests/Services/CouponServiceTest.cs b/src/Orb.Tests/Services/CouponServiceTest.cs new file mode 100644 index 00000000..0f347049 --- /dev/null +++ b/src/Orb.Tests/Services/CouponServiceTest.cs @@ -0,0 +1,46 @@ +using System.Threading.Tasks; +using Orb.Models.Coupons; + +namespace Orb.Tests.Services; + +public class CouponServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var coupon = await this.client.Coupons.Create( + new() { Discount = new Percentage(0), RedemptionCode = "HALFOFF" }, + TestContext.Current.CancellationToken + ); + coupon.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Coupons.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Archive_Works() + { + var coupon = await this.client.Coupons.Archive( + "coupon_id", + new(), + TestContext.Current.CancellationToken + ); + coupon.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var coupon = await this.client.Coupons.Fetch( + "coupon_id", + new(), + TestContext.Current.CancellationToken + ); + coupon.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Coupons/SubscriptionServiceTest.cs b/src/Orb.Tests/Services/Coupons/SubscriptionServiceTest.cs new file mode 100644 index 00000000..989eb21c --- /dev/null +++ b/src/Orb.Tests/Services/Coupons/SubscriptionServiceTest.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Coupons; + +public class SubscriptionServiceTest : TestBase +{ + [Fact] + public async Task List_Works() + { + var page = await this.client.Coupons.Subscriptions.List( + "coupon_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } +} diff --git a/src/Orb.Tests/Services/CreditNoteServiceTest.cs b/src/Orb.Tests/Services/CreditNoteServiceTest.cs new file mode 100644 index 00000000..d7f7f50a --- /dev/null +++ b/src/Orb.Tests/Services/CreditNoteServiceTest.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using Orb.Models.CreditNotes; + +namespace Orb.Tests.Services; + +public class CreditNoteServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var creditNote = await this.client.CreditNotes.Create( + new() + { + LineItems = + [ + new() + { + Amount = "amount", + InvoiceLineItemID = "4khy3nwzktxv7", + EndDate = "2023-09-22", + StartDate = "2023-09-22", + }, + ], + Reason = Reason.Duplicate, + }, + TestContext.Current.CancellationToken + ); + creditNote.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.CreditNotes.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var creditNote = await this.client.CreditNotes.Fetch( + "credit_note_id", + new(), + TestContext.Current.CancellationToken + ); + creditNote.Validate(); + } +} diff --git a/src/Orb.Tests/Services/CustomerServiceTest.cs b/src/Orb.Tests/Services/CustomerServiceTest.cs new file mode 100644 index 00000000..f9e201cb --- /dev/null +++ b/src/Orb.Tests/Services/CustomerServiceTest.cs @@ -0,0 +1,97 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class CustomerServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var customer = await this.client.Customers.Create( + new() { Email = "dev@stainless.com", Name = "x" }, + TestContext.Current.CancellationToken + ); + customer.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var customer = await this.client.Customers.Update( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + customer.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Customers.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Delete_Works() + { + await this.client.Customers.Delete( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + } + + [Fact] + public async Task Fetch_Works() + { + var customer = await this.client.Customers.Fetch( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + customer.Validate(); + } + + [Fact] + public async Task FetchByExternalID_Works() + { + var customer = await this.client.Customers.FetchByExternalID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + customer.Validate(); + } + + [Fact] + public async Task SyncPaymentMethodsFromGateway_Works() + { + await this.client.Customers.SyncPaymentMethodsFromGateway( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + } + + [Fact] + public async Task SyncPaymentMethodsFromGatewayByExternalCustomerID_Works() + { + await this.client.Customers.SyncPaymentMethodsFromGatewayByExternalCustomerID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + } + + [Fact] + public async Task UpdateByExternalID_Works() + { + var customer = await this.client.Customers.UpdateByExternalID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + customer.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Customers/BalanceTransactionServiceTest.cs b/src/Orb.Tests/Services/Customers/BalanceTransactionServiceTest.cs new file mode 100644 index 00000000..0d246837 --- /dev/null +++ b/src/Orb.Tests/Services/Customers/BalanceTransactionServiceTest.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Tests.Services.Customers; + +public class BalanceTransactionServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var balanceTransaction = await this.client.Customers.BalanceTransactions.Create( + "customer_id", + new() { Amount = "amount", Type = Type.Increment }, + TestContext.Current.CancellationToken + ); + balanceTransaction.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Customers.BalanceTransactions.List( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Customers/CostServiceTest.cs b/src/Orb.Tests/Services/Customers/CostServiceTest.cs new file mode 100644 index 00000000..ea167f95 --- /dev/null +++ b/src/Orb.Tests/Services/Customers/CostServiceTest.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Customers; + +public class CostServiceTest : TestBase +{ + [Fact] + public async Task List_Works() + { + var costs = await this.client.Customers.Costs.List( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + costs.Validate(); + } + + [Fact] + public async Task ListByExternalID_Works() + { + var response = await this.client.Customers.Costs.ListByExternalID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Customers/CreditServiceTest.cs b/src/Orb.Tests/Services/Customers/CreditServiceTest.cs new file mode 100644 index 00000000..218985b8 --- /dev/null +++ b/src/Orb.Tests/Services/Customers/CreditServiceTest.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Customers; + +public class CreditServiceTest : TestBase +{ + [Fact] + public async Task List_Works() + { + var page = await this.client.Customers.Credits.List( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } + + [Fact] + public async Task ListByExternalID_Works() + { + var page = await this.client.Customers.Credits.ListByExternalID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Customers/Credits/LedgerServiceTest.cs b/src/Orb.Tests/Services/Customers/Credits/LedgerServiceTest.cs new file mode 100644 index 00000000..9107a7ba --- /dev/null +++ b/src/Orb.Tests/Services/Customers/Credits/LedgerServiceTest.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Tests.Services.Customers.Credits; + +public class LedgerServiceTest : TestBase +{ + [Fact] + public async Task List_Works() + { + var page = await this.client.Customers.Credits.Ledger.List( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } + + [Fact] + public async Task CreateEntry_Works() + { + var response = await this.client.Customers.Credits.Ledger.CreateEntry( + "customer_id", + new() + { + Body = new Increment() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = Field.ItemID, + Operator = Operator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }, + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task CreateEntryByExternalID_Works() + { + var response = await this.client.Customers.Credits.Ledger.CreateEntryByExternalID( + "external_customer_id", + new() + { + Body = new LedgerCreateEntryByExternalIDParamsBodyIncrement() + { + Amount = 0, + Currency = "currency", + Description = "description", + EffectiveDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + ExpiryDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + Filters = + [ + new() + { + Field = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + Operator = + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + Values = ["string"], + }, + ], + InvoiceSettings = new() + { + AutoCollection = true, + CustomDueDate = "2019-12-27", + InvoiceDate = "2019-12-27", + ItemID = "item_id", + Memo = "memo", + NetTerms = 0, + RequireSuccessfulPayment = true, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + PerUnitCostBasis = "per_unit_cost_basis", + }, + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task ListByExternalID_Works() + { + var page = await this.client.Customers.Credits.Ledger.ListByExternalID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Customers/Credits/TopUpServiceTest.cs b/src/Orb.Tests/Services/Customers/Credits/TopUpServiceTest.cs new file mode 100644 index 00000000..c9bdf0a0 --- /dev/null +++ b/src/Orb.Tests/Services/Customers/Credits/TopUpServiceTest.cs @@ -0,0 +1,96 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Customers.Credits; + +public class TopUpServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var topUp = await this.client.Customers.Credits.TopUps.Create( + "customer_id", + new() + { + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }, + TestContext.Current.CancellationToken + ); + topUp.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Customers.Credits.TopUps.List( + "customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } + + [Fact] + public async Task Delete_Works() + { + await this.client.Customers.Credits.TopUps.Delete( + "top_up_id", + new() { CustomerID = "customer_id" }, + TestContext.Current.CancellationToken + ); + } + + [Fact] + public async Task CreateByExternalID_Works() + { + var response = await this.client.Customers.Credits.TopUps.CreateByExternalID( + "external_customer_id", + new() + { + Amount = "amount", + Currency = "currency", + InvoiceSettings = new() + { + AutoCollection = true, + NetTerms = 0, + Memo = "memo", + RequireSuccessfulPayment = true, + }, + PerUnitCostBasis = "per_unit_cost_basis", + Threshold = "threshold", + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task DeleteByExternalID_Works() + { + await this.client.Customers.Credits.TopUps.DeleteByExternalID( + "top_up_id", + new() { ExternalCustomerID = "external_customer_id" }, + TestContext.Current.CancellationToken + ); + } + + [Fact] + public async Task ListByExternalID_Works() + { + var page = await this.client.Customers.Credits.TopUps.ListByExternalID( + "external_customer_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } +} diff --git a/src/Orb.Tests/Services/DimensionalPriceGroupServiceTest.cs b/src/Orb.Tests/Services/DimensionalPriceGroupServiceTest.cs new file mode 100644 index 00000000..7710f1c1 --- /dev/null +++ b/src/Orb.Tests/Services/DimensionalPriceGroupServiceTest.cs @@ -0,0 +1,53 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class DimensionalPriceGroupServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var dimensionalPriceGroup = await this.client.DimensionalPriceGroups.Create( + new() + { + BillableMetricID = "billable_metric_id", + Dimensions = ["region", "instance_type"], + Name = "name", + }, + TestContext.Current.CancellationToken + ); + dimensionalPriceGroup.Validate(); + } + + [Fact] + public async Task Retrieve_Works() + { + var dimensionalPriceGroup = await this.client.DimensionalPriceGroups.Retrieve( + "dimensional_price_group_id", + new(), + TestContext.Current.CancellationToken + ); + dimensionalPriceGroup.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var dimensionalPriceGroup = await this.client.DimensionalPriceGroups.Update( + "dimensional_price_group_id", + new(), + TestContext.Current.CancellationToken + ); + dimensionalPriceGroup.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.DimensionalPriceGroups.List( + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } +} diff --git a/src/Orb.Tests/Services/DimensionalPriceGroups/ExternalDimensionalPriceGroupIDServiceTest.cs b/src/Orb.Tests/Services/DimensionalPriceGroups/ExternalDimensionalPriceGroupIDServiceTest.cs new file mode 100644 index 00000000..9ef909db --- /dev/null +++ b/src/Orb.Tests/Services/DimensionalPriceGroups/ExternalDimensionalPriceGroupIDServiceTest.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.DimensionalPriceGroups; + +public class ExternalDimensionalPriceGroupIDServiceTest : TestBase +{ + [Fact] + public async Task Retrieve_Works() + { + var dimensionalPriceGroup = + await this.client.DimensionalPriceGroups.ExternalDimensionalPriceGroupID.Retrieve( + "external_dimensional_price_group_id", + new(), + TestContext.Current.CancellationToken + ); + dimensionalPriceGroup.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var dimensionalPriceGroup = + await this.client.DimensionalPriceGroups.ExternalDimensionalPriceGroupID.Update( + "external_dimensional_price_group_id", + new(), + TestContext.Current.CancellationToken + ); + dimensionalPriceGroup.Validate(); + } +} diff --git a/src/Orb.Tests/Services/EventServiceTest.cs b/src/Orb.Tests/Services/EventServiceTest.cs new file mode 100644 index 00000000..cfaecfed --- /dev/null +++ b/src/Orb.Tests/Services/EventServiceTest.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class EventServiceTest : TestBase +{ + [Fact] + public async Task Update_Works() + { + var event1 = await this.client.Events.Update( + "event_id", + new() + { + EventName = "event_name", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + }, + TestContext.Current.CancellationToken + ); + event1.Validate(); + } + + [Fact] + public async Task Deprecate_Works() + { + var response = await this.client.Events.Deprecate( + "event_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Ingest_Works() + { + var response = await this.client.Events.Ingest( + new() + { + Events = + [ + new() + { + EventName = "event_name", + IdempotencyKey = "idempotency_key", + Properties = new Dictionary() + { + { "foo", JsonSerializer.SerializeToElement("bar") }, + }, + Timestamp = DateTimeOffset.Parse("2020-12-09T16:09:53Z"), + CustomerID = "customer_id", + ExternalCustomerID = "external_customer_id", + }, + ], + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Search_Works() + { + var response = await this.client.Events.Search( + new() { EventIDs = ["string"] }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Events/BackfillServiceTest.cs b/src/Orb.Tests/Services/Events/BackfillServiceTest.cs new file mode 100644 index 00000000..0ed19bcb --- /dev/null +++ b/src/Orb.Tests/Services/Events/BackfillServiceTest.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Events; + +public class BackfillServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var backfill = await this.client.Events.Backfills.Create( + new() + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + TestContext.Current.CancellationToken + ); + backfill.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Events.Backfills.List( + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } + + [Fact] + public async Task Close_Works() + { + var response = await this.client.Events.Backfills.Close( + "backfill_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var response = await this.client.Events.Backfills.Fetch( + "backfill_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Revert_Works() + { + var response = await this.client.Events.Backfills.Revert( + "backfill_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Events/VolumeServiceTest.cs b/src/Orb.Tests/Services/Events/VolumeServiceTest.cs new file mode 100644 index 00000000..8869aee5 --- /dev/null +++ b/src/Orb.Tests/Services/Events/VolumeServiceTest.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Events; + +public class VolumeServiceTest : TestBase +{ + [Fact] + public async Task List_Works() + { + var eventVolumes = await this.client.Events.Volume.List( + new() { TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z") }, + TestContext.Current.CancellationToken + ); + eventVolumes.Validate(); + } +} diff --git a/src/Orb.Tests/Services/InvoiceLineItemServiceTest.cs b/src/Orb.Tests/Services/InvoiceLineItemServiceTest.cs new file mode 100644 index 00000000..c6da638c --- /dev/null +++ b/src/Orb.Tests/Services/InvoiceLineItemServiceTest.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class InvoiceLineItemServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var invoiceLineItem = await this.client.InvoiceLineItems.Create( + new() + { + Amount = "12.00", + EndDate = "2023-09-22", + InvoiceID = "4khy3nwzktxv7", + Quantity = 1, + StartDate = "2023-09-22", + }, + TestContext.Current.CancellationToken + ); + invoiceLineItem.Validate(); + } +} diff --git a/src/Orb.Tests/Services/InvoiceServiceTest.cs b/src/Orb.Tests/Services/InvoiceServiceTest.cs new file mode 100644 index 00000000..b05ffebd --- /dev/null +++ b/src/Orb.Tests/Services/InvoiceServiceTest.cs @@ -0,0 +1,118 @@ +using System; +using System.Threading.Tasks; +using Orb.Models.Invoices; + +namespace Orb.Tests.Services; + +public class InvoiceServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var invoice = await this.client.Invoices.Create( + new() + { + Currency = "USD", + InvoiceDate = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + LineItems = + [ + new() + { + EndDate = "2023-09-22", + ItemID = "4khy3nwzktxv7", + ModelType = ModelType.Unit, + Name = "Line Item Name", + Quantity = 1, + StartDate = "2023-09-22", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + }, + ], + }, + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var invoice = await this.client.Invoices.Update( + "invoice_id", + new(), + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Invoices.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var invoice = await this.client.Invoices.Fetch( + "invoice_id", + new(), + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } + + [Fact] + public async Task FetchUpcoming_Works() + { + var response = await this.client.Invoices.FetchUpcoming( + new() { SubscriptionID = "subscription_id" }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Issue_Works() + { + var invoice = await this.client.Invoices.Issue( + "invoice_id", + new(), + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } + + [Fact] + public async Task MarkPaid_Works() + { + var invoice = await this.client.Invoices.MarkPaid( + "invoice_id", + new() { PaymentReceivedDate = "2023-09-22" }, + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } + + [Fact] + public async Task Pay_Works() + { + var invoice = await this.client.Invoices.Pay( + "invoice_id", + new(), + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } + + [Fact] + public async Task Void_Works() + { + var invoice = await this.client.Invoices.Void( + "invoice_id", + new(), + TestContext.Current.CancellationToken + ); + invoice.Validate(); + } +} diff --git a/src/Orb.Tests/Services/ItemServiceTest.cs b/src/Orb.Tests/Services/ItemServiceTest.cs new file mode 100644 index 00000000..8ade7cd8 --- /dev/null +++ b/src/Orb.Tests/Services/ItemServiceTest.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class ItemServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var item = await this.client.Items.Create( + new() { Name = "API requests" }, + TestContext.Current.CancellationToken + ); + item.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var item = await this.client.Items.Update( + "item_id", + new(), + TestContext.Current.CancellationToken + ); + item.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Items.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Archive_Works() + { + var item = await this.client.Items.Archive( + "item_id", + new(), + TestContext.Current.CancellationToken + ); + item.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var item = await this.client.Items.Fetch( + "item_id", + new(), + TestContext.Current.CancellationToken + ); + item.Validate(); + } +} diff --git a/src/Orb.Tests/Services/MetricServiceTest.cs b/src/Orb.Tests/Services/MetricServiceTest.cs new file mode 100644 index 00000000..004845e5 --- /dev/null +++ b/src/Orb.Tests/Services/MetricServiceTest.cs @@ -0,0 +1,51 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class MetricServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var billableMetric = await this.client.Metrics.Create( + new() + { + Description = "Sum of bytes downloaded in fast mode", + ItemID = "item_id", + Name = "Bytes downloaded", + Sql = "SELECT sum(bytes_downloaded) FROM events WHERE download_speed = 'fast'", + }, + TestContext.Current.CancellationToken + ); + billableMetric.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var billableMetric = await this.client.Metrics.Update( + "metric_id", + new(), + TestContext.Current.CancellationToken + ); + billableMetric.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Metrics.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var billableMetric = await this.client.Metrics.Fetch( + "metric_id", + new(), + TestContext.Current.CancellationToken + ); + billableMetric.Validate(); + } +} diff --git a/src/Orb.Tests/Services/PlanServiceTest.cs b/src/Orb.Tests/Services/PlanServiceTest.cs new file mode 100644 index 00000000..8df29ba7 --- /dev/null +++ b/src/Orb.Tests/Services/PlanServiceTest.cs @@ -0,0 +1,121 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Orb.Models; + +namespace Orb.Tests.Services; + +public class PlanServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var plan = await this.client.Plans.Create( + new() + { + Currency = "currency", + Name = "name", + Prices = + [ + new() + { + AllocationPrice = new() + { + Amount = "10.00", + Cadence = Cadence.Monthly, + Currency = "USD", + CustomExpiration = new() + { + Duration = 0, + DurationUnit = CustomExpirationDurationUnit.Day, + }, + ExpiresAtEndOfCadence = true, + Filters = + [ + new() + { + Field = NewAllocationPriceFilterField.ItemID, + Operator = NewAllocationPriceFilterOperator.Includes, + Values = ["string"], + }, + ], + ItemID = "item_id", + PerUnitCostBasis = "per_unit_cost_basis", + }, + PlanPhaseOrder = 0, + PriceValue = new NewPlanUnitPrice() + { + Cadence = NewPlanUnitPriceCadence.Annual, + ItemID = "item_id", + ModelType = NewPlanUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = + SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + Currency = "currency", + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = + "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + ReferenceID = "reference_id", + }, + }, + ], + }, + TestContext.Current.CancellationToken + ); + plan.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var plan = await this.client.Plans.Update( + "plan_id", + new(), + TestContext.Current.CancellationToken + ); + plan.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Plans.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var plan = await this.client.Plans.Fetch( + "plan_id", + new(), + TestContext.Current.CancellationToken + ); + plan.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Plans/ExternalPlanIDServiceTest.cs b/src/Orb.Tests/Services/Plans/ExternalPlanIDServiceTest.cs new file mode 100644 index 00000000..1aea5814 --- /dev/null +++ b/src/Orb.Tests/Services/Plans/ExternalPlanIDServiceTest.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Plans; + +public class ExternalPlanIDServiceTest : TestBase +{ + [Fact] + public async Task Update_Works() + { + var plan = await this.client.Plans.ExternalPlanID.Update( + "external_plan_id", + new(), + TestContext.Current.CancellationToken + ); + plan.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var plan = await this.client.Plans.ExternalPlanID.Fetch( + "external_plan_id", + new(), + TestContext.Current.CancellationToken + ); + plan.Validate(); + } +} diff --git a/src/Orb.Tests/Services/PriceServiceTest.cs b/src/Orb.Tests/Services/PriceServiceTest.cs new file mode 100644 index 00000000..bf53a364 --- /dev/null +++ b/src/Orb.Tests/Services/PriceServiceTest.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Orb.Models; + +namespace Orb.Tests.Services; + +public class PriceServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var price = await this.client.Prices.Create( + new() + { + Body = new NewFloatingUnitPrice() + { + Cadence = NewFloatingUnitPriceCadence.Annual, + Currency = "currency", + ItemID = "item_id", + ModelType = NewFloatingUnitPriceModelType.Unit, + Name = "Annual fee", + UnitConfig = new() { UnitAmount = "unit_amount", Prorated = true }, + BillableMetricID = "billable_metric_id", + BilledInAdvance = true, + BillingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + ConversionRate = 0, + ConversionRateConfig = new SharedUnitConversionRateConfig() + { + ConversionRateType = SharedUnitConversionRateConfigConversionRateType.Unit, + UnitConfig = new("unit_amount"), + }, + DimensionalPriceConfiguration = new() + { + DimensionValues = ["string"], + DimensionalPriceGroupID = "dimensional_price_group_id", + ExternalDimensionalPriceGroupID = "external_dimensional_price_group_id", + }, + ExternalPriceID = "external_price_id", + FixedPriceQuantity = 0, + InvoiceGroupingKey = "x", + InvoicingCycleConfiguration = new() + { + Duration = 0, + DurationUnit = NewBillingCycleConfigurationDurationUnit.Day, + }, + Metadata = new Dictionary() { { "foo", "string" } }, + }, + }, + TestContext.Current.CancellationToken + ); + price.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var price = await this.client.Prices.Update( + "price_id", + new(), + TestContext.Current.CancellationToken + ); + price.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Prices.List(new(), TestContext.Current.CancellationToken); + page.Validate(); + } + + [Fact] + public async Task Evaluate_Works() + { + var response = await this.client.Prices.Evaluate( + "price_id", + new() + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task EvaluateMultiple_Works() + { + var response = await this.client.Prices.EvaluateMultiple( + new() + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task EvaluatePreviewEvents_Works() + { + var response = await this.client.Prices.EvaluatePreviewEvents( + new() + { + TimeframeEnd = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + TimeframeStart = DateTimeOffset.Parse("2019-12-27T18:11:19.117Z"), + }, + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var price = await this.client.Prices.Fetch( + "price_id", + new(), + TestContext.Current.CancellationToken + ); + price.Validate(); + } +} diff --git a/src/Orb.Tests/Services/Prices/ExternalPriceIDServiceTest.cs b/src/Orb.Tests/Services/Prices/ExternalPriceIDServiceTest.cs new file mode 100644 index 00000000..6377d01f --- /dev/null +++ b/src/Orb.Tests/Services/Prices/ExternalPriceIDServiceTest.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services.Prices; + +public class ExternalPriceIDServiceTest : TestBase +{ + [Fact] + public async Task Update_Works() + { + var price = await this.client.Prices.ExternalPriceID.Update( + "external_price_id", + new(), + TestContext.Current.CancellationToken + ); + price.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var price = await this.client.Prices.ExternalPriceID.Fetch( + "external_price_id", + new(), + TestContext.Current.CancellationToken + ); + price.Validate(); + } +} diff --git a/src/Orb.Tests/Services/SubscriptionChangeServiceTest.cs b/src/Orb.Tests/Services/SubscriptionChangeServiceTest.cs new file mode 100644 index 00000000..1bbb4a29 --- /dev/null +++ b/src/Orb.Tests/Services/SubscriptionChangeServiceTest.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class SubscriptionChangeServiceTest : TestBase +{ + [Fact] + public async Task Retrieve_Works() + { + var subscriptionChange = await this.client.SubscriptionChanges.Retrieve( + "subscription_change_id", + new(), + TestContext.Current.CancellationToken + ); + subscriptionChange.Validate(); + } + + [Fact] + public async Task Apply_Works() + { + var response = await this.client.SubscriptionChanges.Apply( + "subscription_change_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task Cancel_Works() + { + var response = await this.client.SubscriptionChanges.Cancel( + "subscription_change_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } +} diff --git a/src/Orb.Tests/Services/SubscriptionServiceTest.cs b/src/Orb.Tests/Services/SubscriptionServiceTest.cs new file mode 100644 index 00000000..fc7c1eb6 --- /dev/null +++ b/src/Orb.Tests/Services/SubscriptionServiceTest.cs @@ -0,0 +1,193 @@ +using System; +using System.Threading.Tasks; +using Orb.Models.Subscriptions; + +namespace Orb.Tests.Services; + +public class SubscriptionServiceTest : TestBase +{ + [Fact] + public async Task Create_Works() + { + var mutatedSubscription = await this.client.Subscriptions.Create( + new(), + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task Update_Works() + { + var subscription = await this.client.Subscriptions.Update( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + subscription.Validate(); + } + + [Fact] + public async Task List_Works() + { + var page = await this.client.Subscriptions.List( + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } + + [Fact] + public async Task Cancel_Works() + { + var mutatedSubscription = await this.client.Subscriptions.Cancel( + "subscription_id", + new() { CancelOption = CancelOption.EndOfSubscriptionTerm }, + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task Fetch_Works() + { + var subscription = await this.client.Subscriptions.Fetch( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + subscription.Validate(); + } + + [Fact] + public async Task FetchCosts_Works() + { + var response = await this.client.Subscriptions.FetchCosts( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } + + [Fact] + public async Task FetchSchedule_Works() + { + var page = await this.client.Subscriptions.FetchSchedule( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + page.Validate(); + } + + [Fact(Skip = "Incorrect example breaks Prism")] + public async Task FetchUsage_Works() + { + var subscriptionUsage = await this.client.Subscriptions.FetchUsage( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + subscriptionUsage.Validate(); + } + + [Fact(Skip = "Incorrect example breaks Prism")] + public async Task PriceIntervals_Works() + { + var mutatedSubscription = await this.client.Subscriptions.PriceIntervals( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task RedeemCoupon_Works() + { + var mutatedSubscription = await this.client.Subscriptions.RedeemCoupon( + "subscription_id", + new() { ChangeOption = ChangeOption.RequestedDate }, + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task SchedulePlanChange_Works() + { + var mutatedSubscription = await this.client.Subscriptions.SchedulePlanChange( + "subscription_id", + new() { ChangeOption = SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate }, + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task TriggerPhase_Works() + { + var mutatedSubscription = await this.client.Subscriptions.TriggerPhase( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task UnscheduleCancellation_Works() + { + var mutatedSubscription = await this.client.Subscriptions.UnscheduleCancellation( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task UnscheduleFixedFeeQuantityUpdates_Works() + { + var mutatedSubscription = await this.client.Subscriptions.UnscheduleFixedFeeQuantityUpdates( + "subscription_id", + new() { PriceID = "price_id" }, + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task UnschedulePendingPlanChanges_Works() + { + var mutatedSubscription = await this.client.Subscriptions.UnschedulePendingPlanChanges( + "subscription_id", + new(), + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task UpdateFixedFeeQuantity_Works() + { + var mutatedSubscription = await this.client.Subscriptions.UpdateFixedFeeQuantity( + "subscription_id", + new() { PriceID = "price_id", Quantity = 0 }, + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } + + [Fact] + public async Task UpdateTrial_Works() + { + var mutatedSubscription = await this.client.Subscriptions.UpdateTrial( + "subscription_id", + new() { TrialEndDate = DateTimeOffset.Parse("2017-07-21T17:32:28Z") }, + TestContext.Current.CancellationToken + ); + mutatedSubscription.Validate(); + } +} diff --git a/src/Orb.Tests/Services/TopLevelServiceTest.cs b/src/Orb.Tests/Services/TopLevelServiceTest.cs new file mode 100644 index 00000000..999db27b --- /dev/null +++ b/src/Orb.Tests/Services/TopLevelServiceTest.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; + +namespace Orb.Tests.Services; + +public class TopLevelServiceTest : TestBase +{ + [Fact] + public async Task Ping_Works() + { + var response = await this.client.TopLevel.Ping( + new(), + TestContext.Current.CancellationToken + ); + response.Validate(); + } +} diff --git a/src/Orb.Tests/TestBase.cs b/src/Orb.Tests/TestBase.cs index f5a96be9..972702c8 100644 --- a/src/Orb.Tests/TestBase.cs +++ b/src/Orb.Tests/TestBase.cs @@ -1,20 +1,18 @@ -using Orb = Orb; -using System = System; +using System; +using Orb; namespace Orb.Tests; public class TestBase { - protected Orb::IOrbClient client; + protected IOrbClient client; public TestBase() { - client = new Orb::OrbClient() + client = new OrbClient() { - BaseUrl = new System::Uri( - System::Environment.GetEnvironmentVariable("TEST_API_BASE_URL") - ?? "http://localhost:4010" - ), + BaseUrl = + Environment.GetEnvironmentVariable("TEST_API_BASE_URL") ?? "http://localhost:4010", APIKey = "My API Key", }; } diff --git a/src/Orb/Core/ApiEnum.cs b/src/Orb/Core/ApiEnum.cs new file mode 100644 index 00000000..85a11dcf --- /dev/null +++ b/src/Orb/Core/ApiEnum.cs @@ -0,0 +1,110 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; + +namespace Orb.Core; + +/// +/// A serializable and deserializable enum wrapper type that handles the possibility of values outside the +/// range of known enum members. +/// +/// In most cases you don't have to worry about this type and can rely on its implicit operators to +/// wrap and unwrap enum values. +/// +/// +/// Returns this instance's raw value. +/// +/// This is usually only useful if this instance was deserialized from data that doesn't match the +/// expected type (), and you want to know that value. For example, if the +/// SDK is on an older version than the API, then the API may respond with new data types that the SDK is +/// unaware of. +/// +/// +public record class ApiEnum(JsonElement Json) + where TEnum : struct, Enum +{ + /// + /// Returns this instance's raw value. + /// + /// This is usually only useful if this instance was deserialized from data that doesn't match + /// any known enum member, and you want to know that value. For example, if the SDK is on an older + /// version than the API, then the API may respond with new members that the SDK is unaware of. + /// + /// + /// Thrown when this instance's raw value isn't of type . Use + /// to access the raw value. + /// + /// + public TRaw Raw() => + JsonSerializer.Deserialize(this.Json, ModelBase.SerializerOptions) + ?? throw new OrbInvalidDataException( + string.Format("{0} cannot be null", nameof(this.Json)) + ); + + /// + /// Returns an enum member corresponding to this instance's value, or (TEnum)(-1) if the + /// class was instantiated with an unknown value. + /// + /// Use to access the raw value.. + /// + public TEnum Value() => + JsonSerializer.Deserialize(this.Json, ModelBase.SerializerOptions); + + /// + /// Verifies that this instance's raw value is a member of . + /// + /// + /// Thrown when this instance's raw value isn't a member of . + /// + /// + public void Validate() + { + if (!Enum.IsDefined(typeof(TEnum), Value())) + { + throw new OrbInvalidDataException("Invalid enum value"); + } + } + + public virtual bool Equals(ApiEnum? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } + + public static implicit operator TRaw(ApiEnum value) => value.Raw(); + + public static implicit operator TEnum(ApiEnum value) => value.Value(); + + public static implicit operator ApiEnum(TRaw value) => + new(JsonSerializer.SerializeToElement(value, ModelBase.SerializerOptions)); + + public static implicit operator ApiEnum(TEnum value) => + new(JsonSerializer.SerializeToElement(value, ModelBase.SerializerOptions)); +} + +sealed class ApiEnumConverter : JsonConverter> + where TEnum : struct, Enum +{ + public override ApiEnum Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + return new(JsonSerializer.Deserialize(ref reader, options)); + } + + public override void Write( + Utf8JsonWriter writer, + ApiEnum value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Core/BinaryContent.cs b/src/Orb/Core/BinaryContent.cs new file mode 100644 index 00000000..0da5d45a --- /dev/null +++ b/src/Orb/Core/BinaryContent.cs @@ -0,0 +1,25 @@ +using System.IO; +using System.Net.Http.Headers; + +namespace Orb.Core; + +/// +/// A class representing a binary stream of data with its associated (optional) file +/// name and content type. +/// +public sealed record class BinaryContent +{ + public required Stream Stream { get; init; } + public string? FileName { get; init; } + public MediaTypeHeaderValue ContentType { get; set; } = new("application/octet-stream"); + + public static implicit operator BinaryContent(Stream stream) => + new() + { + Stream = stream, + FileName = stream is FileStream fileStream ? Path.GetFileName(fileStream.Name) : null, + }; + + public static implicit operator BinaryContent(byte[] bytes) => + new() { Stream = new MemoryStream(bytes) }; +} diff --git a/src/Orb/Core/ClientOptions.cs b/src/Orb/Core/ClientOptions.cs new file mode 100644 index 00000000..a0f4109a --- /dev/null +++ b/src/Orb/Core/ClientOptions.cs @@ -0,0 +1,103 @@ +using System; +using System.Net.Http; +using Orb.Exceptions; + +namespace Orb.Core; + +/// +/// A class representing the SDK client configuration. +/// +public struct ClientOptions() +{ + /// + /// The default value used for . + /// + public static readonly int DefaultMaxRetries = 2; + + /// + /// The default value used for . + /// + public static readonly TimeSpan DefaultTimeout = TimeSpan.FromMinutes(1); + + /// + /// The HTTP client to use for making requests in the SDK. + /// + public HttpClient HttpClient { get; set; } = new(); + + Lazy _baseUrl = new(() => + Environment.GetEnvironmentVariable("ORB_BASE_URL") ?? EnvironmentUrl.Production + ); + + /// + /// The base URL to use for every request. + /// + /// Defaults to the production environment: + /// + public string BaseUrl + { + readonly get { return _baseUrl.Value; } + set { _baseUrl = new(() => value); } + } + + /// + /// Whether to validate every response before returning it. + /// + /// Defaults to false, which means the shape of the response will not be + /// validated upfront. Instead, validation will only occur for the parts of the + /// response that are accessed. + /// + public bool ResponseValidation { get; set; } = false; + + /// + /// The maximum number of times to retry failed requests, with a short exponential backoff between requests. + /// + /// + /// Only the following error types are retried: + /// + /// Connection errors (for example, due to a network connectivity problem) + /// 408 Request Timeout + /// 409 Conflict + /// 429 Rate Limit + /// 5xx Internal + /// + /// + /// + /// The API may also explicitly instruct the SDK to retry or not retry a request. + /// + /// Defaults to 2 when null. Set to 0 to + /// disable retries, which also ignores API instructions to retry. + /// + public int? MaxRetries { get; set; } + + /// + /// Sets the maximum time allowed for a complete HTTP call, not including retries. + /// + /// This includes resolving DNS, connecting, writing the request body, server processing, as + /// well as reading the response body. + /// + /// Defaults to TimeSpan.FromMinutes(1) when null. + /// + public TimeSpan? Timeout { get; set; } + + Lazy _apiKey = new(() => + Environment.GetEnvironmentVariable("ORB_API_KEY") + ?? throw new OrbInvalidDataException( + string.Format("{0} cannot be null", nameof(APIKey)), + new ArgumentNullException(nameof(APIKey)) + ) + ); + public string APIKey + { + readonly get { return _apiKey.Value; } + set { _apiKey = new(() => value); } + } + + Lazy _webhookSecret = new(() => + Environment.GetEnvironmentVariable("ORB_WEBHOOK_SECRET") + ); + public string? WebhookSecret + { + readonly get { return _webhookSecret.Value; } + set { _webhookSecret = new(() => value); } + } +} diff --git a/src/Orb/Core/EnvironmentUrl.cs b/src/Orb/Core/EnvironmentUrl.cs new file mode 100644 index 00000000..b0fbe187 --- /dev/null +++ b/src/Orb/Core/EnvironmentUrl.cs @@ -0,0 +1,6 @@ +namespace Orb.Core; + +public static class EnvironmentUrl +{ + public static readonly string Production = "https://api.withorb.com/v1"; +} diff --git a/src/Orb/Core/FreezableDictionary.cs b/src/Orb/Core/FreezableDictionary.cs new file mode 100644 index 00000000..298697cd --- /dev/null +++ b/src/Orb/Core/FreezableDictionary.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Collections = System.Collections; + +namespace Orb.Core; + +/// +/// A dictionary that can be mutated and then frozen once no more mutations are expected. +/// +/// This is useful for allowing a dictionary to be modified by a class's init +/// properties, but then preventing it from being modified afterwards. +/// +class FreezableDictionary : IDictionary + where K : notnull +{ + IDictionary _dictionary = new Dictionary(); + + Dictionary _mutableDictionary + { + get + { + if (_dictionary is Dictionary dict) + { + return dict; + } + + throw new InvalidOperationException("Can't mutate after freezing."); + } + } + + public FreezableDictionary() { } + + public FreezableDictionary(IReadOnlyDictionary dictionary) + { + _dictionary = Enumerable.ToDictionary(dictionary, e => e.Key, e => e.Value); + } + + public FreezableDictionary(FrozenDictionary frozen) + { + _dictionary = frozen; + } + + /// + /// Freezes this dictionary and returns a readonly view of it. + /// + /// Future calls to mutating methods on this class will throw + /// . + /// + public IReadOnlyDictionary Freeze() + { + if (_dictionary is FrozenDictionary dict) + { + return dict; + } + + var dictionary = FrozenDictionary.ToFrozenDictionary(_dictionary); + _dictionary = dictionary; + + return dictionary; + } + + /// + public V this[K key] + { + get => _dictionary[key]; + set => _mutableDictionary[key] = value; + } + + /// + public ICollection Keys + { + get { return _dictionary.Keys; } + } + + /// + public ICollection Values + { + get { return _dictionary.Values; } + } + + /// + public int Count + { + get { return _dictionary.Count; } + } + + /// + public bool IsReadOnly + { + get { return _dictionary.IsReadOnly; } + } + + /// + public void Add(K key, V value) + { + _mutableDictionary.Add(key, value); + } + + /// + public void Add(KeyValuePair item) + { + _mutableDictionary.Add(item.Key, item.Value); + } + + /// + public void Clear() + { + _mutableDictionary.Clear(); + } + + /// + public bool Contains(KeyValuePair item) + { + return _dictionary.Contains(item); + } + + /// + public bool ContainsKey(K key) + { + return _dictionary.ContainsKey(key); + } + + /// + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + _dictionary.CopyTo(array, arrayIndex); + } + + /// + public IEnumerator> GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + + /// + public bool Remove(K key) + { + return _mutableDictionary.Remove(key); + } + + /// + public bool Remove(KeyValuePair item) + { + return _mutableDictionary.Remove(item.Key); + } + + /// + public bool TryGetValue(K key, +#if NET + [MaybeNullWhen(false)] +#endif + + out V value) + { + return _dictionary.TryGetValue(key, out value); + } + + /// + Collections::IEnumerator Collections::IEnumerable.GetEnumerator() + { + return _dictionary.GetEnumerator(); + } +} diff --git a/src/Orb/Core/HttpRequest.cs b/src/Orb/Core/HttpRequest.cs new file mode 100644 index 00000000..4bc2ce98 --- /dev/null +++ b/src/Orb/Core/HttpRequest.cs @@ -0,0 +1,11 @@ +using System.Net.Http; + +namespace Orb.Core; + +public sealed class HttpRequest

+ where P : ParamsBase +{ + public required HttpMethod Method { get; init; } + + public required P Params { get; init; } +} diff --git a/src/Orb/Core/HttpResponse.cs b/src/Orb/Core/HttpResponse.cs new file mode 100644 index 00000000..298e3075 --- /dev/null +++ b/src/Orb/Core/HttpResponse.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Orb.Exceptions; + +namespace Orb.Core; + +public sealed class HttpResponse : IDisposable +{ + public required HttpResponseMessage Message { get; init; } + + public CancellationToken CancellationToken { get; init; } = default; + + public async Task Deserialize(CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource( + this.CancellationToken, + cancellationToken + ); + try + { + return await JsonSerializer + .DeserializeAsync( + await this.ReadAsStream(cts.Token).ConfigureAwait(false), + ModelBase.SerializerOptions, + cts.Token + ) + .ConfigureAwait(false) + ?? throw new OrbInvalidDataException("Response cannot be null"); + } + catch (HttpRequestException e) + { + throw new OrbIOException("I/O Exception", e); + } + } + + public async Task ReadAsStream(CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource( + this.CancellationToken, + cancellationToken + ); + return await Message.Content.ReadAsStreamAsync( +#if NET + cts.Token +#endif + ).ConfigureAwait(false); + } + + public async Task ReadAsString(CancellationToken cancellationToken = default) + { + using var cts = CancellationTokenSource.CreateLinkedTokenSource( + this.CancellationToken, + cancellationToken + ); + return await Message.Content.ReadAsStringAsync( +#if NET + cts.Token +#endif + ).ConfigureAwait(false); + } + + public void Dispose() => this.Message.Dispose(); +} diff --git a/src/Orb/Core/IPage.cs b/src/Orb/Core/IPage.cs new file mode 100644 index 00000000..ad421e7d --- /dev/null +++ b/src/Orb/Core/IPage.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Exceptions; + +namespace Orb.Core; + +///

+/// An interface representing a single page, with items of type , from a +/// paginated endpoint response. +/// +public interface IPage +{ + /// + /// The items in this page. + /// + IReadOnlyList Items { get; } + + /// + /// Returns whether there's another page after this one. + /// + /// The method doesn't make requests so the result depends entirely on the + /// data in this page. If a significant amount of time has passed between requesting + /// this page and calling this method, then the result could be stale. + /// + bool HasNext(); + + /// + /// Returns the page after this one by making another request. + /// + /// + /// Thrown when it's impossible to get the next page. This exception is avoidable by calling + /// first. + /// + /// + Task> Next(CancellationToken cancellationToken = default); + + /// + /// Validates that the page was constructed with a valid response (based on its own + /// Validate method). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + void Validate(); + +#if NET + /// + public IAsyncEnumerable Paginate(CancellationToken cancellationToken = default) => + IPageExtensions.Paginate(this, cancellationToken); +#endif +} diff --git a/src/Orb/Core/JsonModel.cs b/src/Orb/Core/JsonModel.cs new file mode 100644 index 00000000..ca2c7fa5 --- /dev/null +++ b/src/Orb/Core/JsonModel.cs @@ -0,0 +1,174 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Exceptions; + +namespace Orb.Core; + +/// +/// The base class for all API objects that are serialized as JSON objects. +/// +/// API objects such as enums and unions do not inherit from this class. +/// +public abstract record class JsonModel : ModelBase +{ + private protected FreezableDictionary _rawData = []; + + protected JsonModel(JsonModel jsonModel) + : base(jsonModel) + { + this._rawData = [.. jsonModel._rawData]; + } + + /// + /// The backing JSON properties of the instance. + /// + public IReadOnlyDictionary RawData + { + get { return this._rawData.Freeze(); } + } + + internal static void Set(IDictionary dictionary, string key, T value) + { + dictionary[key] = JsonSerializer.SerializeToElement(value, SerializerOptions); + } + + internal static T GetNotNullClass( + IReadOnlyDictionary dictionary, + string key + ) + where T : class + { + if (!dictionary.TryGetValue(key, out var element)) + { + throw new OrbInvalidDataException($"'{key}' cannot be absent"); + } + + try + { + return JsonSerializer.Deserialize(element, SerializerOptions) + ?? throw new OrbInvalidDataException($"'{key}' cannot be null"); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + internal static T GetNotNullStruct( + IReadOnlyDictionary dictionary, + string key + ) + where T : struct + { + if (!dictionary.TryGetValue(key, out var element)) + { + throw new OrbInvalidDataException($"'{key}' cannot be absent"); + } + + try + { + return JsonSerializer.Deserialize(element, SerializerOptions) + ?? throw new OrbInvalidDataException($"'{key}' cannot be null"); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + internal static T? GetNullableClass( + IReadOnlyDictionary dictionary, + string key + ) + where T : class + { + if (!dictionary.TryGetValue(key, out var element)) + { + return null; + } + + try + { + return JsonSerializer.Deserialize(element, SerializerOptions); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + internal static T? GetNullableStruct( + IReadOnlyDictionary dictionary, + string key + ) + where T : struct + { + if (!dictionary.TryGetValue(key, out var element)) + { + return null; + } + + try + { + return JsonSerializer.Deserialize(element, SerializerOptions); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + public sealed override string ToString() => + JsonSerializer.Serialize(this.RawData, ToStringSerializerOptions); + + public virtual bool Equals(JsonModel? other) + { + if (other == null || this.RawData.Count != other.RawData.Count) + { + return false; + } + + foreach (var item in this.RawData) + { + if (!other.RawData.TryGetValue(item.Key, out var otherValue)) + { + return false; + } + + if (!JsonElement.DeepEquals(item.Value, otherValue)) + { + return false; + } + } + + return true; + } + + public override int GetHashCode() + { + return 0; + } +} + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +/// NOTE: This interface is in the style of a factory instance instead of using +/// abstract static methods because .NET Standard 2.0 doesn't support abstract static methods. +/// +interface IFromRawJson +{ + /// + /// Returns an instance constructed from the given raw JSON properties. + /// + /// Required field and type mismatches are not checked. In these cases accessing + /// the relevant properties of the constructed instance may throw. + /// + /// This method is useful for constructing an instance from already serialized + /// data or for sending arbitrary data to the API (e.g. for undocumented or not + /// yet supported properties or values). + /// + T FromRawUnchecked(IReadOnlyDictionary rawData); +} diff --git a/src/Orb/Core/JsonModelConverter.cs b/src/Orb/Core/JsonModelConverter.cs new file mode 100644 index 00000000..c14633ca --- /dev/null +++ b/src/Orb/Core/JsonModelConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Orb.Core; + +sealed class JsonModelConverter : JsonConverter + where TModel : JsonModel + where TFromRaw : IFromRawJson, new() +{ + public override TModel? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var rawData = JsonSerializer.Deserialize>( + ref reader, + options + ); + if (rawData == null) + return null; + + return new TFromRaw().FromRawUnchecked(rawData); + } + + public override void Write(Utf8JsonWriter writer, TModel value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.RawData, options); + } +} diff --git a/src/Orb/Core/ModelBase.cs b/src/Orb/Core/ModelBase.cs new file mode 100644 index 00000000..97bb4197 --- /dev/null +++ b/src/Orb/Core/ModelBase.cs @@ -0,0 +1,910 @@ +using System.Text.Json; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Customers.Costs; +using Orb.Models.Customers.Credits.TopUps; +using Orb.Models.Items; +using Alerts = Orb.Models.Alerts; +using Backfills = Orb.Models.Events.Backfills; +using BalanceTransactions = Orb.Models.Customers.BalanceTransactions; +using Beta = Orb.Models.Beta; +using CreditNotes = Orb.Models.CreditNotes; +using Credits = Orb.Models.Customers.Credits; +using Customers = Orb.Models.Customers; +using ExternalPlanID = Orb.Models.Beta.ExternalPlanID; +using Invoices = Orb.Models.Invoices; +using Ledger = Orb.Models.Customers.Credits.Ledger; +using Metrics = Orb.Models.Metrics; +using Plans = Orb.Models.Plans; +using Prices = Orb.Models.Prices; +using SubscriptionChanges = Orb.Models.SubscriptionChanges; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Core; + +/// +/// The base class for all API objects with properties. +/// +/// API objects such as enums and unions do not inherit from this class. +/// +public abstract record class ModelBase +{ + protected ModelBase(ModelBase modelBase) + { + // Nothing to copy. Just so that subclasses can define copy constructors. + } + + internal static readonly JsonSerializerOptions SerializerOptions = new() + { + Converters = + { + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + NewFloatingScalableMatrixWithTieredPricingPriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + ScalableMatrixWithUnitPricingCompositePriceFilterOperator + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + ScalableMatrixWithTieredPricingCompositePriceFilterField + >(), + new ApiEnumConverter< + string, + ScalableMatrixWithTieredPricingCompositePriceFilterOperator + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Beta::ReplacePricePriceGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + Beta::ReplacePricePriceCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + ExternalPlanID::ReplacePricePriceTieredWithProrationCadence + >(), + new ApiEnumConverter< + string, + ExternalPlanID::ReplacePricePriceGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + ExternalPlanID::ReplacePricePriceCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Customers::CustomerPaymentConfigurationPaymentProviderProviderType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Customers::CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType + >(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Customers::CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + >(), + new ApiEnumConverter< + string, + Customers::CustomerUpdateByExternalIDParamsPaymentProvider + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Ledger::LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField + >(), + new ApiEnumConverter< + string, + Ledger::LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator + >(), + new ApiEnumConverter< + string, + Ledger::LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + BalanceTransactions::BalanceTransactionCreateResponseType + >(), + new ApiEnumConverter< + string, + BalanceTransactions::BalanceTransactionListResponseAction + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Prices::PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + >(), + new ApiEnumConverter< + string, + Prices::PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + Prices::PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter< + string, + Prices::PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence + >(), + new ApiEnumConverter< + string, + Prices::PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionBulkWithProrationPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionBulkWithProrationPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionCumulativeGroupedBulkPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedAllocationPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedAllocationPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedTieredPackagePriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedTieredPackagePriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedTieredPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionGroupedWithProratedMinimumPriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMatrixWithAllocationPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMatrixWithAllocationPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMatrixWithDisplayNamePriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMaxGroupTieredPackagePriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMinimumCompositePriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionMinimumCompositePriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionPackageWithAllocationPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionPackageWithAllocationPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionThresholdTotalAmountPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionThresholdTotalAmountPriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionTieredPackagePriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionTieredPackageWithMinimumPriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionTieredWithMinimumPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionTieredWithMinimumPriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionUnitWithPercentPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionUnitWithPercentPriceModelType + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionUnitWithProrationPriceCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::NewSubscriptionUnitWithProrationPriceModelType + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::ReplacePricePriceTieredWithProrationCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::ReplacePricePriceGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::ReplacePricePriceCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::PriceModelGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::PriceModelCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsChangeOption + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + >(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + >(), + new ApiEnumConverter< + string, + Subscriptions::SubscriptionUpdateFixedFeeQuantityParamsChangeOption + >(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter< + string, + SubscriptionChanges::SubscriptionChangeRetrieveResponseStatus + >(), + new ApiEnumConverter< + string, + SubscriptionChanges::SubscriptionChangeApplyResponseStatus + >(), + new ApiEnumConverter< + string, + SubscriptionChanges::SubscriptionChangeCancelResponseStatus + >(), + }, + }; + + private protected static readonly JsonSerializerOptions ToStringSerializerOptions = new( + SerializerOptions + ) + { + WriteIndented = true, + }; + + /// + /// Validates that all required fields are set and that each field's value is of the expected type. + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public abstract void Validate(); +} diff --git a/src/Orb/Core/MultipartJsonElement.cs b/src/Orb/Core/MultipartJsonElement.cs new file mode 100644 index 00000000..4d997908 --- /dev/null +++ b/src/Orb/Core/MultipartJsonElement.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading; + +namespace Orb.Core; + +/// +/// A that can contain . +/// +/// Use to construct or read instances of this class. +/// +public readonly struct MultipartJsonElement() +{ + /// + /// A with placeholders + /// for . + /// + internal JsonElement Json { get; init; } + + /// + /// A dictionary from placeholder string in the JSON to + /// . + /// + internal IReadOnlyDictionary BinaryContents { get; init; } = + FrozenDictionary.ToFrozenDictionary(new Dictionary()); + + public static implicit operator MultipartJsonElement(JsonElement json) => new() { Json = json }; +} + +/// +/// A serializer for mixed JSON and binary content. +/// +public static class MultipartJsonSerializer +{ + /// + /// The current dictionary from placeholder string to to use for + /// serialization/deserialization. + /// + /// This isn't a local variable because we want to share + /// for performance. It's also a thread local to avoid data races between threads. + /// + static readonly ThreadLocal?> CurrentBinaryContents = new(() => + null + ); + + internal static Dictionary BinaryContents + { + get + { + return CurrentBinaryContents.Value + ?? throw new InvalidOperationException( + "Cannot convert BinaryContent without MultipartJsonSerializer" + ); + } + } + + static readonly ThreadLocal< + Dictionary + > MultipartSerializerOptionsCache = new(() => []); + + static readonly JsonSerializerOptions DefaultMultipartSerializerOptions = + MultipartSerializerOptions(new()); + + static JsonSerializerOptions MultipartSerializerOptions(JsonSerializerOptions? options = null) + { + if (options == null) + { + return DefaultMultipartSerializerOptions; + } + + if (!MultipartSerializerOptionsCache.Value!.TryGetValue(options, out var multipartOptions)) + { + multipartOptions = new(options); + multipartOptions.Converters.Add(new BinaryContentConverter()); + multipartOptions.Converters.Add(new MultipartJsonElementConverter()); + MultipartSerializerOptionsCache.Value![options] = multipartOptions; + } + + return multipartOptions; + } + + public static MultipartJsonElement SerializeToElement( + T value, + JsonSerializerOptions? options = null + ) + { + var previousBinaryContents = CurrentBinaryContents.Value; + try + { + CurrentBinaryContents.Value = []; + var element = JsonSerializer.SerializeToElement( + value, + MultipartSerializerOptions(options) + ); + return new() + { + Json = element, + BinaryContents = FrozenDictionary.ToFrozenDictionary(CurrentBinaryContents.Value!), + }; + } + finally + { + CurrentBinaryContents.Value = previousBinaryContents; + } + } + + public static T? Deserialize( + MultipartJsonElement element, + JsonSerializerOptions? options = null + ) + { + var previousBinaryContents = CurrentBinaryContents.Value; + try + { + CurrentBinaryContents.Value = Enumerable.ToDictionary( + element.BinaryContents, + e => e.Key, + e => e.Value + ); + return JsonSerializer.Deserialize(element.Json, MultipartSerializerOptions(options)); + } + finally + { + CurrentBinaryContents.Value = previousBinaryContents; + } + } + + public static MultipartFormDataContent Serialize( + T value, + JsonSerializerOptions? options = null + ) + { + MultipartFormDataContent formDataContent = []; + var multipartElement = MultipartJsonSerializer.SerializeToElement(value, options); + void SerializeParts(string name, JsonElement element) + { + HttpContent content; + string? fileName = null; + switch (element.ValueKind) + { + case JsonValueKind.Undefined: + case JsonValueKind.Null: + return; + case JsonValueKind.Number: + content = new StringContent(element.ToString()); + break; + case JsonValueKind.String: + if ( + element.TryGetGuid(out var guid) + && multipartElement.BinaryContents.TryGetValue(guid, out var binaryContent) + ) + { + content = new StreamContent(binaryContent.Stream); + content.Headers.ContentType = binaryContent.ContentType; + fileName = binaryContent.FileName; + } + else + { + content = new StringContent(element.ToString()); + } + break; + case JsonValueKind.True: + content = new StringContent("true"); + break; + case JsonValueKind.False: + content = new StringContent("false"); + break; + case JsonValueKind.Object: + foreach (var item in element.EnumerateObject()) + { + SerializeParts( + name == "" ? item.Name : string.Format("{0}[{1}]", name, item.Name), + item.Value + ); + } + return; + case JsonValueKind.Array: + foreach (var item in element.EnumerateArray()) + { + SerializeParts(string.Format("{0}[]", name), item); + } + return; + default: + throw new ArgumentOutOfRangeException(nameof(element)); + } + if (name == "") + { + formDataContent.Add(content); + } + else if (fileName == null) + { + formDataContent.Add(content, name); + } + else + { + formDataContent.Add(content, name, fileName); + } + } + SerializeParts("", multipartElement.Json); + return formDataContent; + } +} + +/// +/// A JSON converter that serializes/deserializes mixed JSON and binary content. +/// +/// It uses placeholder IDs (see ), which are written/read +/// to/from a thread-local dictionary, so it's expected that this converter is only invoked via +/// , which ensures the dictionary is set up correctly. +/// +sealed class MultipartJsonElementConverter : JsonConverter +{ + public override MultipartJsonElement Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) => + new() + { + Json = JsonSerializer.Deserialize(ref reader, options), + BinaryContents = MultipartJsonSerializer.BinaryContents, + }; + + public override void Write( + Utf8JsonWriter writer, + MultipartJsonElement value, + JsonSerializerOptions options + ) + { + foreach (var item in value.BinaryContents) + { + MultipartJsonSerializer.BinaryContents.Add(item.Key, item.Value); + } + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// A JSON converter that serializes/deserializes binary content to/from placeholder IDs. +/// +/// The placeholder IDs are written/read to/from a thread-local dictionary, so it's expected that +/// this converter is only invoked via , which ensures the +/// dictionary is set up correctly. +/// +sealed class BinaryContentConverter : JsonConverter +{ + public override BinaryContent Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) => + MultipartJsonSerializer.BinaryContents[ + JsonSerializer.Deserialize(ref reader, options) + ]; + + public override void Write( + Utf8JsonWriter writer, + BinaryContent value, + JsonSerializerOptions options + ) + { + var guid = Guid.NewGuid(); + MultipartJsonSerializer.BinaryContents[guid] = value; + JsonSerializer.Serialize(writer, guid, options); + } +} diff --git a/src/Orb/Core/MultipartJsonModel.cs b/src/Orb/Core/MultipartJsonModel.cs new file mode 100644 index 00000000..c699db59 --- /dev/null +++ b/src/Orb/Core/MultipartJsonModel.cs @@ -0,0 +1,156 @@ +using System.Collections.Generic; +using System.Text.Json; +using Orb.Exceptions; + +namespace Orb.Core; + +/// +/// The base class for all API objects that are serialized as a mix of JSON objects +/// and binary content. +/// +/// API objects such as enums and unions do not inherit from this class. +/// +public abstract record class MultipartJsonModel : ModelBase +{ + private protected FreezableDictionary _rawData = []; + + protected MultipartJsonModel(MultipartJsonModel jsonModel) + : base(jsonModel) + { + this._rawData = [.. jsonModel._rawData]; + } + + /// + /// The backing mix of JSON and binary content properties of the instance. + /// + public IReadOnlyDictionary RawData + { + get { return this._rawData.Freeze(); } + } + + internal static void Set( + IDictionary dictionary, + string key, + T value + ) + { + dictionary[key] = MultipartJsonSerializer.SerializeToElement( + value, + ModelBase.SerializerOptions + ); + } + + internal static T GetNotNullClass( + IReadOnlyDictionary dictionary, + string key + ) + where T : class + { + if (!dictionary.TryGetValue(key, out var element)) + { + throw new OrbInvalidDataException($"'{key}' cannot be absent"); + } + + try + { + return MultipartJsonSerializer.Deserialize(element) + ?? throw new OrbInvalidDataException($"'{key}' cannot be null"); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + internal static T GetNotNullStruct( + IReadOnlyDictionary dictionary, + string key + ) + where T : struct + { + if (!dictionary.TryGetValue(key, out var element)) + { + throw new OrbInvalidDataException($"'{key}' cannot be absent"); + } + + try + { + return MultipartJsonSerializer.Deserialize(element) + ?? throw new OrbInvalidDataException($"'{key}' cannot be null"); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + internal static T? GetNullableClass( + IReadOnlyDictionary dictionary, + string key + ) + where T : class + { + if (!dictionary.TryGetValue(key, out var element)) + { + return null; + } + + try + { + return MultipartJsonSerializer.Deserialize(element); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + internal static T? GetNullableStruct( + IReadOnlyDictionary dictionary, + string key + ) + where T : struct + { + if (!dictionary.TryGetValue(key, out var element)) + { + return null; + } + + try + { + return MultipartJsonSerializer.Deserialize(element); + } + catch (JsonException e) + { + throw new OrbInvalidDataException($"'{key}' must be of type {typeof(T).FullName}", e); + } + } + + public override int GetHashCode() + { + return 0; + } +} + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +/// NOTE: This interface is in the style of a factory instance instead of using +/// abstract static methods because .NET Standard 2.0 doesn't support abstract static methods. +/// +interface IFromRawMultipartJson +{ + /// + /// Returns an instance constructed from the given raw JSON properties. + /// + /// Required field and type mismatches are not checked. In these cases accessing + /// the relevant properties of the constructed instance may throw. + /// + /// This method is useful for constructing an instance from already serialized + /// data or for sending arbitrary data to the API (e.g. for undocumented or not + /// yet supported properties or values). + /// + T FromRawUnchecked(IReadOnlyDictionary rawData); +} diff --git a/src/Orb/Core/MultipartJsonModelConverter.cs b/src/Orb/Core/MultipartJsonModelConverter.cs new file mode 100644 index 00000000..f5f2cf1f --- /dev/null +++ b/src/Orb/Core/MultipartJsonModelConverter.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Orb.Core; + +sealed class MultipartJsonModelConverter : JsonConverter + where TModel : MultipartJsonModel + where TFromRaw : IFromRawMultipartJson, new() +{ + public override TModel? Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options + ) + { + var rawData = JsonSerializer.Deserialize>( + ref reader, + options + ); + if (rawData == null) + return null; + + return new TFromRaw().FromRawUnchecked(rawData); + } + + public override void Write(Utf8JsonWriter writer, TModel value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.RawData, options); + } +} diff --git a/src/Orb/Core/ParamsBase.cs b/src/Orb/Core/ParamsBase.cs new file mode 100644 index 00000000..29440243 --- /dev/null +++ b/src/Orb/Core/ParamsBase.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Net.Http; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json; +using System.Web; + +namespace Orb.Core; + +public abstract record class ParamsBase +{ + static readonly IReadOnlyDictionary defaultHeaders; + + static ParamsBase() + { + var runtime = GetRuntime(); + defaultHeaders = new Dictionary + { + ["User-Agent"] = GetUserAgent(), + ["X-Stainless-Arch"] = GetOSArch(), + ["X-Stainless-Lang"] = "csharp", + ["X-Stainless-OS"] = GetOS(), + ["X-Stainless-Package-Version"] = GetPackageVersion(), + ["X-Stainless-Runtime"] = runtime.Name, + ["X-Stainless-Runtime-Version"] = runtime.Version, + }; + } + + private protected FreezableDictionary _rawQueryData = []; + + private protected FreezableDictionary _rawHeaderData = []; + + protected ParamsBase(ParamsBase paramsBase) + { + this._rawHeaderData = [.. paramsBase._rawHeaderData]; + this._rawQueryData = [.. paramsBase._rawQueryData]; + } + + public IReadOnlyDictionary RawQueryData + { + get { return this._rawQueryData.Freeze(); } + } + + public IReadOnlyDictionary RawHeaderData + { + get { return this._rawHeaderData.Freeze(); } + } + + public abstract Uri Url(ClientOptions options); + + protected static void AddQueryElementToCollection( + NameValueCollection collection, + string key, + JsonElement element + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Undefined: + case JsonValueKind.Null: + collection.Add(key, ""); + break; + case JsonValueKind.String: + case JsonValueKind.Number: + collection.Add(key, element.ToString()); + break; + case JsonValueKind.True: + collection.Add(key, "true"); + break; + case JsonValueKind.False: + collection.Add(key, "false"); + break; + case JsonValueKind.Object: + foreach (var item in element.EnumerateObject()) + { + AddQueryElementToCollection( + collection, + string.Format("{0}[{1}]", key, item.Name), + item.Value + ); + } + break; + case JsonValueKind.Array: + foreach (var item in element.EnumerateArray()) + { + collection.Add( + string.Format("{0}[]", key), + item.ValueKind switch + { + JsonValueKind.Null => "", + JsonValueKind.True => "true", + JsonValueKind.False => "false", + _ => item.GetString(), + } + ); + } + break; + } + } + + protected static void AddHeaderElementToRequest( + HttpRequestMessage request, + string key, + JsonElement element + ) + { + switch (element.ValueKind) + { + case JsonValueKind.Undefined: + case JsonValueKind.Null: + request.Headers.Add(key, ""); + break; + case JsonValueKind.String: + case JsonValueKind.Number: + request.Headers.Add(key, element.ToString()); + break; + case JsonValueKind.True: + request.Headers.Add(key, "true"); + break; + case JsonValueKind.False: + request.Headers.Add(key, "false"); + break; + case JsonValueKind.Object: + foreach (var item in element.EnumerateObject()) + { + AddHeaderElementToRequest( + request, + string.Format("{0}.{1}", key, item.Name), + item.Value + ); + } + break; + case JsonValueKind.Array: + foreach (var item in element.EnumerateArray()) + { + request.Headers.Add( + key, + item.ValueKind switch + { + JsonValueKind.Null => "", + JsonValueKind.True => "true", + JsonValueKind.False => "false", + _ => item.GetString(), + } + ); + } + break; + } + } + + protected string QueryString(ClientOptions options) + { + NameValueCollection collection = []; + foreach (var item in this.RawQueryData) + { + ParamsBase.AddQueryElementToCollection(collection, item.Key, item.Value); + } + StringBuilder sb = new(); + bool first = true; + foreach (var key in collection.AllKeys) + { + foreach (var value in collection.GetValues(key) ?? []) + { + if (!first) + { + sb.Append('&'); + } + first = false; + sb.Append(HttpUtility.UrlEncode(key)); + sb.Append('='); + sb.Append(HttpUtility.UrlEncode(value)); + } + } + return sb.ToString(); + } + + internal abstract void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options); + + internal virtual HttpContent? BodyContent() + { + return null; + } + + protected static void AddDefaultHeaders(HttpRequestMessage request, ClientOptions options) + { + foreach (var header in defaultHeaders) + { + request.Headers.Add(header.Key, header.Value); + } + + if (options.APIKey != null) + { + request.Headers.Add("Authorization", string.Format("Bearer {0}", options.APIKey)); + } + request.Headers.Add( + "X-Stainless-Timeout", + (options.Timeout ?? ClientOptions.DefaultTimeout).TotalSeconds.ToString() + ); + } + + static string GetUserAgent() => $"{typeof(OrbClient).Name}/C# {GetPackageVersion()}"; + + static string GetOSArch() => + RuntimeInformation.OSArchitecture switch + { + Architecture.X86 => "x32", + Architecture.X64 => "x64", + Architecture.Arm => "arm", + Architecture.Arm64 => "arm64", +#if !NETSTANDARD2_0 + Architecture.Armv6 => "arm64", + Architecture.Wasm + or Architecture.S390x + or Architecture.LoongArch64 + or Architecture.Ppc64le => $"other:{RuntimeInformation.OSArchitecture}", +#endif + _ => "unknown", + }; + + static string GetOS() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return "Windows"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return "MacOS"; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return "Linux"; + } + return $"Other:{RuntimeInformation.OSDescription}"; + } + + static string GetPackageVersion() => + Assembly + .GetExecutingAssembly() + .GetCustomAttribute() + ?.InformationalVersion + ?? "unknown"; + + static Runtime GetRuntime() + { + var runtimeDescription = RuntimeInformation.FrameworkDescription; + var lastSpaceIndex = runtimeDescription.LastIndexOf(' '); + if (lastSpaceIndex == -1) + { + return new() { Name = runtimeDescription, Version = "unknown" }; + } + + var name = runtimeDescription.Substring(0, lastSpaceIndex).Trim(); + var version = runtimeDescription.Substring(lastSpaceIndex + 1).Trim(); + return new() + { + Name = name.Length == 0 ? "unknown" : name, + Version = version.Length == 0 ? "unknown" : version, + }; + } + + readonly record struct Runtime(string Name, string Version); +} diff --git a/src/Orb/Exceptions/Orb4xxException.cs b/src/Orb/Exceptions/Orb4xxException.cs new file mode 100644 index 00000000..96269e97 --- /dev/null +++ b/src/Orb/Exceptions/Orb4xxException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class Orb4xxException : OrbApiException +{ + public Orb4xxException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/Orb5xxException.cs b/src/Orb/Exceptions/Orb5xxException.cs new file mode 100644 index 00000000..d935ba5b --- /dev/null +++ b/src/Orb/Exceptions/Orb5xxException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class Orb5xxException : OrbApiException +{ + public Orb5xxException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbApiException.cs b/src/Orb/Exceptions/OrbApiException.cs new file mode 100644 index 00000000..c3421604 --- /dev/null +++ b/src/Orb/Exceptions/OrbApiException.cs @@ -0,0 +1,35 @@ +using System; +using System.Net; +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbApiException : OrbException +{ + public new HttpRequestException InnerException + { + get + { + if (base.InnerException == null) + { + throw new ArgumentNullException(); + } + return (HttpRequestException)base.InnerException; + } + } + + public OrbApiException(string message, HttpRequestException? innerException = null) + : base(message, innerException) { } + + protected OrbApiException(HttpRequestException? innerException) + : base(innerException) { } + + public required HttpStatusCode StatusCode { get; init; } + + public required string ResponseBody { get; init; } + + public override string Message + { + get { return string.Format("Status Code: {0}\n{1}", StatusCode, ResponseBody); } + } +} diff --git a/src/Orb/Exceptions/OrbBadRequestException.cs b/src/Orb/Exceptions/OrbBadRequestException.cs new file mode 100644 index 00000000..3ecc9f09 --- /dev/null +++ b/src/Orb/Exceptions/OrbBadRequestException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbBadRequestException : Orb4xxException +{ + public OrbBadRequestException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbException.cs b/src/Orb/Exceptions/OrbException.cs new file mode 100644 index 00000000..ac8b369d --- /dev/null +++ b/src/Orb/Exceptions/OrbException.cs @@ -0,0 +1,13 @@ +using System; +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbException : Exception +{ + public OrbException(string message, Exception? innerException = null) + : base(message, innerException) { } + + protected OrbException(HttpRequestException? innerException) + : base(null, innerException) { } +} diff --git a/src/Orb/Exceptions/OrbExceptionFactory.cs b/src/Orb/Exceptions/OrbExceptionFactory.cs new file mode 100644 index 00000000..5ea98e5d --- /dev/null +++ b/src/Orb/Exceptions/OrbExceptionFactory.cs @@ -0,0 +1,58 @@ +using System.Net; + +namespace Orb.Exceptions; + +public class OrbExceptionFactory +{ + public static OrbApiException CreateApiException(HttpStatusCode statusCode, string responseBody) + { + return (int)statusCode switch + { + 400 => new OrbBadRequestException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + 401 => new OrbUnauthorizedException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + 403 => new OrbForbiddenException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + 404 => new OrbNotFoundException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + 422 => new OrbUnprocessableEntityException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + 429 => new OrbRateLimitException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + >= 400 and <= 499 => new Orb4xxException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + >= 500 and <= 599 => new Orb5xxException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + _ => new OrbUnexpectedStatusCodeException() + { + StatusCode = statusCode, + ResponseBody = responseBody, + }, + }; + } +} diff --git a/src/Orb/Exceptions/OrbForbiddenException.cs b/src/Orb/Exceptions/OrbForbiddenException.cs new file mode 100644 index 00000000..32c83ec3 --- /dev/null +++ b/src/Orb/Exceptions/OrbForbiddenException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbForbiddenException : Orb4xxException +{ + public OrbForbiddenException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbIOException.cs b/src/Orb/Exceptions/OrbIOException.cs new file mode 100644 index 00000000..15e5b4ab --- /dev/null +++ b/src/Orb/Exceptions/OrbIOException.cs @@ -0,0 +1,22 @@ +using System; +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbIOException : OrbException +{ + public new HttpRequestException InnerException + { + get + { + if (base.InnerException == null) + { + throw new ArgumentNullException(); + } + return (HttpRequestException)base.InnerException; + } + } + + public OrbIOException(string message, HttpRequestException? innerException = null) + : base(message, innerException) { } +} diff --git a/src/Orb/Exceptions/OrbInvalidDataException.cs b/src/Orb/Exceptions/OrbInvalidDataException.cs new file mode 100644 index 00000000..2b42c163 --- /dev/null +++ b/src/Orb/Exceptions/OrbInvalidDataException.cs @@ -0,0 +1,9 @@ +using System; + +namespace Orb.Exceptions; + +public class OrbInvalidDataException : OrbException +{ + public OrbInvalidDataException(string message, Exception? innerException = null) + : base(message, innerException) { } +} diff --git a/src/Orb/Exceptions/OrbNotFoundException.cs b/src/Orb/Exceptions/OrbNotFoundException.cs new file mode 100644 index 00000000..b6b60623 --- /dev/null +++ b/src/Orb/Exceptions/OrbNotFoundException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbNotFoundException : Orb4xxException +{ + public OrbNotFoundException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbRateLimitException.cs b/src/Orb/Exceptions/OrbRateLimitException.cs new file mode 100644 index 00000000..6c45dc17 --- /dev/null +++ b/src/Orb/Exceptions/OrbRateLimitException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbRateLimitException : Orb4xxException +{ + public OrbRateLimitException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbUnauthorizedException.cs b/src/Orb/Exceptions/OrbUnauthorizedException.cs new file mode 100644 index 00000000..6b832f07 --- /dev/null +++ b/src/Orb/Exceptions/OrbUnauthorizedException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbUnauthorizedException : Orb4xxException +{ + public OrbUnauthorizedException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbUnexpectedStatusCodeException.cs b/src/Orb/Exceptions/OrbUnexpectedStatusCodeException.cs new file mode 100644 index 00000000..39249352 --- /dev/null +++ b/src/Orb/Exceptions/OrbUnexpectedStatusCodeException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbUnexpectedStatusCodeException : OrbApiException +{ + public OrbUnexpectedStatusCodeException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/Exceptions/OrbUnprocessableEntityException.cs b/src/Orb/Exceptions/OrbUnprocessableEntityException.cs new file mode 100644 index 00000000..247722a1 --- /dev/null +++ b/src/Orb/Exceptions/OrbUnprocessableEntityException.cs @@ -0,0 +1,9 @@ +using System.Net.Http; + +namespace Orb.Exceptions; + +public class OrbUnprocessableEntityException : Orb4xxException +{ + public OrbUnprocessableEntityException(HttpRequestException? innerException = null) + : base(innerException) { } +} diff --git a/src/Orb/HttpException.cs b/src/Orb/HttpException.cs deleted file mode 100644 index 1e80f5bd..00000000 --- a/src/Orb/HttpException.cs +++ /dev/null @@ -1,29 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Net = System.Net; -using System = System; - -namespace Orb; - -public sealed class HttpException : System::Exception -{ - public required Net::HttpStatusCode? StatusCode { get; set; } - public required string ResponseBody { get; set; } - public override string Message - { - get - { - return string.Format( - "Status Code: {0}\n{1}", - this.StatusCode?.ToString() ?? "Unknown", - this.ResponseBody - ); - } - } - - [CodeAnalysis::SetsRequiredMembers] - public HttpException(Net::HttpStatusCode? statusCode, string responseBody) - { - this.StatusCode = statusCode; - this.ResponseBody = responseBody; - } -} diff --git a/src/Orb/IEnum.cs b/src/Orb/IEnum.cs deleted file mode 100644 index 63ae7156..00000000 --- a/src/Orb/IEnum.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Orb; - -public interface IEnum - where IE : IEnum -{ - static abstract IE FromRaw(T value); - T Raw(); -} diff --git a/src/Orb/IOrbClient.cs b/src/Orb/IOrbClient.cs index 8cc9e40d..9fb5d8c5 100644 --- a/src/Orb/IOrbClient.cs +++ b/src/Orb/IOrbClient.cs @@ -1,61 +1,127 @@ -using Alerts = Orb.Service.Alerts; -using Beta = Orb.Service.Beta; -using Coupons = Orb.Service.Coupons; -using CreditNotes = Orb.Service.CreditNotes; -using Customers = Orb.Service.Customers; -using DimensionalPriceGroups = Orb.Service.DimensionalPriceGroups; -using Events = Orb.Service.Events; -using Http = System.Net.Http; -using InvoiceLineItems = Orb.Service.InvoiceLineItems; -using Invoices = Orb.Service.Invoices; -using Items = Orb.Service.Items; -using Metrics = Orb.Service.Metrics; -using Plans = Orb.Service.Plans; -using Prices = Orb.Service.Prices; -using SubscriptionChanges = Orb.Service.SubscriptionChanges; -using Subscriptions = Orb.Service.Subscriptions; -using System = System; -using TopLevel = Orb.Service.TopLevel; +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Services; namespace Orb; -public interface IOrbClient +/// +/// A client for interacting with the Orb REST API. +/// +/// This client performs best when you create a single instance and reuse it +/// for all interactions with the REST API. This is because each client holds its +/// own connection pool and thread pools. Reusing connections and threads reduces +/// latency and saves memory. +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with +/// breaking changes in non-major versions. We may add new methods in the future that +/// cause existing derived classes to break. +/// +public interface IOrbClient : IDisposable { - Http::HttpClient HttpClient { get; init; } - - System::Uri BaseUrl { get; init; } + /// + /// The HTTP client to use for making requests in the SDK. + /// + HttpClient HttpClient { get; init; } + + /// + /// The base URL to use for every request. + /// + /// Defaults to the production environment: + /// + string BaseUrl { get; init; } + + /// + /// Whether to validate every response before returning it. + /// + /// Defaults to false, which means the shape of the response will not be + /// validated upfront. Instead, validation will only occur for the parts of the + /// response that are accessed. + /// + bool ResponseValidation { get; init; } + + /// + /// The maximum number of times to retry failed requests, with a short exponential backoff between requests. + /// + /// + /// Only the following error types are retried: + /// + /// Connection errors (for example, due to a network connectivity problem) + /// 408 Request Timeout + /// 409 Conflict + /// 429 Rate Limit + /// 5xx Internal + /// + /// + /// + /// The API may also explicitly instruct the SDK to retry or not retry a request. + /// + /// Defaults to 2 when null. Set to 0 to + /// disable retries, which also ignores API instructions to retry. + /// + int? MaxRetries { get; init; } + + /// + /// Sets the maximum time allowed for a complete HTTP call, not including retries. + /// + /// This includes resolving DNS, connecting, writing the request body, server processing, as + /// well as reading the response body. + /// + /// Defaults to TimeSpan.FromMinutes(1) when null. + /// + TimeSpan? Timeout { get; init; } string APIKey { get; init; } - TopLevel::ITopLevelService TopLevel { get; } + string? WebhookSecret { get; init; } + + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IOrbClient WithOptions(Func modifier); + + ITopLevelService TopLevel { get; } + + IBetaService Beta { get; } - Beta::IBetaService Beta { get; } + ICouponService Coupons { get; } - Coupons::ICouponService Coupons { get; } + ICreditNoteService CreditNotes { get; } - CreditNotes::ICreditNoteService CreditNotes { get; } + ICustomerService Customers { get; } - Customers::ICustomerService Customers { get; } + IEventService Events { get; } - Events::IEventService Events { get; } + IInvoiceLineItemService InvoiceLineItems { get; } - InvoiceLineItems::IInvoiceLineItemService InvoiceLineItems { get; } + IInvoiceService Invoices { get; } - Invoices::IInvoiceService Invoices { get; } + IItemService Items { get; } - Items::IItemService Items { get; } + IMetricService Metrics { get; } - Metrics::IMetricService Metrics { get; } + IPlanService Plans { get; } - Plans::IPlanService Plans { get; } + IPriceService Prices { get; } - Prices::IPriceService Prices { get; } + ISubscriptionService Subscriptions { get; } - Subscriptions::ISubscriptionService Subscriptions { get; } + IAlertService Alerts { get; } - Alerts::IAlertService Alerts { get; } + IDimensionalPriceGroupService DimensionalPriceGroups { get; } - DimensionalPriceGroups::IDimensionalPriceGroupService DimensionalPriceGroups { get; } + ISubscriptionChangeService SubscriptionChanges { get; } - SubscriptionChanges::ISubscriptionChangeService SubscriptionChanges { get; } + /// + /// Sends a request to the Orb REST API. + /// + Task Execute( + HttpRequest request, + CancellationToken cancellationToken = default + ) + where T : ParamsBase; } diff --git a/src/Orb/IPageExtensions.cs b/src/Orb/IPageExtensions.cs new file mode 100644 index 00000000..a3612810 --- /dev/null +++ b/src/Orb/IPageExtensions.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using Orb.Core; + +namespace Orb; + +public static class IPageExtensions +{ + /// + /// Returns a lazy async enumerable that auto-paginates by yielding the given + /// page's data and then requesting and yielding additional pages from the API. + /// + public static async IAsyncEnumerable Paginate( + this IPage page, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + while (true) + { + foreach (var element in page.Items) + { + yield return element; + } + cancellationToken.ThrowIfCancellationRequested(); + if (!page.HasNext()) + { + break; + } + page = await page.Next(cancellationToken); + } + } +} diff --git a/src/Orb/IVariant.cs b/src/Orb/IVariant.cs deleted file mode 100644 index ae0d3a39..00000000 --- a/src/Orb/IVariant.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Orb; - -public interface IVariant - where IV : IVariant -{ - static abstract IV From(T value); - T Value { get; } -} diff --git a/src/Orb/JsonConverters.cs b/src/Orb/JsonConverters.cs deleted file mode 100644 index 72279107..00000000 --- a/src/Orb/JsonConverters.cs +++ /dev/null @@ -1,126 +0,0 @@ -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Linq = System.Linq; -using Reflection = System.Reflection; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb; - -public sealed class ModelConverter : Serialization::JsonConverter - where MB : ModelBase, IFromRaw -{ - public override MB? Read( - ref Json::Utf8JsonReader reader, - System::Type _typeToConvert, - Json::JsonSerializerOptions options - ) - { - Generic::Dictionary? properties = - Json::JsonSerializer.Deserialize>( - ref reader, - options - ); - if (properties == null) - return null; - - return MB.FromRawUnchecked(properties); - } - - public override void Write( - Json::Utf8JsonWriter writer, - MB value, - Json::JsonSerializerOptions options - ) - { - Json::JsonSerializer.Serialize(writer, value.Properties, options); - } -} - -public sealed class EnumConverter : Serialization::JsonConverter - where IE : IEnum -{ - public override IE Read( - ref Json::Utf8JsonReader reader, - System::Type _typeToConvert, - Json::JsonSerializerOptions options - ) - { - return IE.FromRaw(Json::JsonSerializer.Deserialize(ref reader, options)!); - } - - public override void Write( - Json::Utf8JsonWriter writer, - IE value, - Json::JsonSerializerOptions options - ) - { - Json::JsonSerializer.Serialize(writer, value.Raw(), options); - } -} - -public sealed class UnionConverter : Serialization::JsonConverter - where T : class -{ - readonly Generic::List _variantTypes = Linq::Enumerable.ToList( - Linq::Enumerable.Where( - Reflection::Assembly.GetExecutingAssembly().GetTypes(), - type => type.BaseType == typeof(T) - ) - ); - - public override T? Read( - ref Json::Utf8JsonReader reader, - System::Type _typeToConvert, - Json::JsonSerializerOptions options - ) - { - Generic::List exceptions = []; - foreach (var variantType in _variantTypes) - { - try - { - return Json::JsonSerializer.Deserialize(ref reader, variantType, options) as T; - } - catch (Json::JsonException e) - { - exceptions.Add(e); - } - } - throw new System::AggregateException(exceptions); - } - - public override void Write( - Json::Utf8JsonWriter writer, - T value, - Json::JsonSerializerOptions options - ) - { - var variantType = - _variantTypes.Find(type => type == value.GetType()) - ?? throw new System::ArgumentOutOfRangeException(value.GetType().Name); - Json::JsonSerializer.Serialize(writer, value, variantType, options); - } -} - -public sealed class VariantConverter : Serialization::JsonConverter - where IV : IVariant -{ - public override IV Read( - ref Json::Utf8JsonReader reader, - System::Type _typeToConvert, - Json::JsonSerializerOptions options - ) - { - return IV.From(Json::JsonSerializer.Deserialize(ref reader, options)!); - } - - public override void Write( - Json::Utf8JsonWriter writer, - IV value, - Json::JsonSerializerOptions options - ) - { - Json::JsonSerializer.Serialize(writer, value.Value, options); - } -} diff --git a/src/Orb/ModelBase.cs b/src/Orb/ModelBase.cs deleted file mode 100644 index da1f5e6e..00000000 --- a/src/Orb/ModelBase.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Generic = System.Collections.Generic; -using Json = System.Text.Json; - -namespace Orb; - -public abstract record class ModelBase -{ - public Generic::Dictionary Properties { get; set; } = []; - - static readonly Json::JsonSerializerOptions _toStringSerializerOptions = new() - { - WriteIndented = true, - }; - - public sealed override string? ToString() - { - return Json::JsonSerializer.Serialize(this.Properties, _toStringSerializerOptions); - } - - public abstract void Validate(); -} - -public interface IFromRaw -{ - static abstract T FromRawUnchecked(Generic::Dictionary properties); -} diff --git a/src/Orb/Models/Address.cs b/src/Orb/Models/Address.cs index 93a6fd7f..824ad8e7 100644 --- a/src/Orb/Models/Address.cs +++ b/src/Orb/Models/Address.cs @@ -1,93 +1,52 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter
))] -public sealed record class Address : Orb::ModelBase, Orb::IFromRaw
+[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Address : JsonModel { public required string? City { - get - { - if (!this.Properties.TryGetValue("city", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("city", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["city"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "city"); } + init { JsonModel.Set(this._rawData, "city", value); } } public required string? Country { - get - { - if (!this.Properties.TryGetValue("country", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "country", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["country"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "country"); } + init { JsonModel.Set(this._rawData, "country", value); } } public required string? Line1 { - get - { - if (!this.Properties.TryGetValue("line1", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("line1", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["line1"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "line1"); } + init { JsonModel.Set(this._rawData, "line1", value); } } public required string? Line2 { - get - { - if (!this.Properties.TryGetValue("line2", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("line2", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["line2"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "line2"); } + init { JsonModel.Set(this._rawData, "line2", value); } } public required string? PostalCode { - get - { - if (!this.Properties.TryGetValue("postal_code", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "postal_code", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["postal_code"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "postal_code"); } + init { JsonModel.Set(this._rawData, "postal_code", value); } } public required string? State { - get - { - if (!this.Properties.TryGetValue("state", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("state", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["state"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "state"); } + init { JsonModel.Set(this._rawData, "state", value); } } + /// public override void Validate() { _ = this.City; @@ -100,18 +59,32 @@ public override void Validate() public Address() { } + public Address(Address address) + : base(address) { } + + public Address(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Address(Generic::Dictionary properties) + [SetsRequiredMembers] + Address(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Address FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static Address FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class AddressFromRaw : IFromRawJson
+{ + /// + public Address FromRawUnchecked(IReadOnlyDictionary rawData) => + Address.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/AdjustmentInterval.cs b/src/Orb/Models/AdjustmentInterval.cs index eb203926..38f23819 100644 --- a/src/Orb/Models/AdjustmentInterval.cs +++ b/src/Orb/Models/AdjustmentInterval.cs @@ -1,136 +1,631 @@ -using AdjustmentIntervalProperties = Orb.Models.AdjustmentIntervalProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AdjustmentInterval : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AdjustmentInterval : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required AdjustmentIntervalProperties::Adjustment Adjustment + public required Adjustment Adjustment { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment"); } + init { JsonModel.Set(this._rawData, "adjustment", value); } } /// /// The price interval IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIntervalIDs + public required IReadOnlyList AppliesToPriceIntervalIDs { get { - if ( - !this.Properties.TryGetValue( - "applies_to_price_interval_ids", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_interval_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_interval_ids"); - } - set - { - this.Properties["applies_to_price_interval_ids"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "applies_to_price_interval_ids" + ); } + init { JsonModel.Set(this._rawData, "applies_to_price_interval_ids", value); } } /// /// The end date of the adjustment interval. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// /// The start date of the adjustment interval. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { _ = this.ID; this.Adjustment.Validate(); - foreach (var item in this.AppliesToPriceIntervalIDs) - { - _ = item; - } + _ = this.AppliesToPriceIntervalIDs; _ = this.EndDate; _ = this.StartDate; } public AdjustmentInterval() { } + public AdjustmentInterval(AdjustmentInterval adjustmentInterval) + : base(adjustmentInterval) { } + + public AdjustmentInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AdjustmentInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + AdjustmentInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static AdjustmentInterval FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AdjustmentIntervalFromRaw : IFromRawJson +{ + /// + public AdjustmentInterval FromRawUnchecked(IReadOnlyDictionary rawData) => + AdjustmentInterval.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(AdjustmentConverter))] +public record class Adjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.ID, + planPhaseAmountDiscount: (x) => x.ID, + planPhasePercentageDiscount: (x) => x.ID, + planPhaseMinimum: (x) => x.ID, + planPhaseMaximum: (x) => x.ID + ); + } + } + + public bool IsInvoiceLevel + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.IsInvoiceLevel, + planPhaseAmountDiscount: (x) => x.IsInvoiceLevel, + planPhasePercentageDiscount: (x) => x.IsInvoiceLevel, + planPhaseMinimum: (x) => x.IsInvoiceLevel, + planPhaseMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public long? PlanPhaseOrder + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.PlanPhaseOrder, + planPhaseAmountDiscount: (x) => x.PlanPhaseOrder, + planPhasePercentageDiscount: (x) => x.PlanPhaseOrder, + planPhaseMinimum: (x) => x.PlanPhaseOrder, + planPhaseMaximum: (x) => x.PlanPhaseOrder + ); + } + } + + public string? Reason + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.Reason, + planPhaseAmountDiscount: (x) => x.Reason, + planPhasePercentageDiscount: (x) => x.Reason, + planPhaseMinimum: (x) => x.Reason, + planPhaseMaximum: (x) => x.Reason + ); + } + } + + public string? ReplacesAdjustmentID + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.ReplacesAdjustmentID, + planPhaseAmountDiscount: (x) => x.ReplacesAdjustmentID, + planPhasePercentageDiscount: (x) => x.ReplacesAdjustmentID, + planPhaseMinimum: (x) => x.ReplacesAdjustmentID, + planPhaseMaximum: (x) => x.ReplacesAdjustmentID + ); + } + } + + public Adjustment(PlanPhaseUsageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(PlanPhaseAmountDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(PlanPhasePercentageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(PlanPhaseMinimumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(PlanPhaseMaximumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseUsageDiscount(out var value)) { + /// // `value` is of type `PlanPhaseUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseUsageDiscount( + [NotNullWhen(true)] out PlanPhaseUsageDiscountAdjustment? value + ) + { + value = this.Value as PlanPhaseUsageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseAmountDiscount(out var value)) { + /// // `value` is of type `PlanPhaseAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseAmountDiscount( + [NotNullWhen(true)] out PlanPhaseAmountDiscountAdjustment? value + ) + { + value = this.Value as PlanPhaseAmountDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhasePercentageDiscount(out var value)) { + /// // `value` is of type `PlanPhasePercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhasePercentageDiscount( + [NotNullWhen(true)] out PlanPhasePercentageDiscountAdjustment? value + ) + { + value = this.Value as PlanPhasePercentageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseMinimum(out var value)) { + /// // `value` is of type `PlanPhaseMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseMinimum([NotNullWhen(true)] out PlanPhaseMinimumAdjustment? value) + { + value = this.Value as PlanPhaseMinimumAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseMaximum(out var value)) { + /// // `value` is of type `PlanPhaseMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseMaximum([NotNullWhen(true)] out PlanPhaseMaximumAdjustment? value) + { + value = this.Value as PlanPhaseMaximumAdjustment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (PlanPhaseUsageDiscountAdjustment value) => {...}, + /// (PlanPhaseAmountDiscountAdjustment value) => {...}, + /// (PlanPhasePercentageDiscountAdjustment value) => {...}, + /// (PlanPhaseMinimumAdjustment value) => {...}, + /// (PlanPhaseMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action planPhaseUsageDiscount, + System::Action planPhaseAmountDiscount, + System::Action planPhasePercentageDiscount, + System::Action planPhaseMinimum, + System::Action planPhaseMaximum + ) + { + switch (this.Value) + { + case PlanPhaseUsageDiscountAdjustment value: + planPhaseUsageDiscount(value); + break; + case PlanPhaseAmountDiscountAdjustment value: + planPhaseAmountDiscount(value); + break; + case PlanPhasePercentageDiscountAdjustment value: + planPhasePercentageDiscount(value); + break; + case PlanPhaseMinimumAdjustment value: + planPhaseMinimum(value); + break; + case PlanPhaseMaximumAdjustment value: + planPhaseMaximum(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (PlanPhaseUsageDiscountAdjustment value) => {...}, + /// (PlanPhaseAmountDiscountAdjustment value) => {...}, + /// (PlanPhasePercentageDiscountAdjustment value) => {...}, + /// (PlanPhaseMinimumAdjustment value) => {...}, + /// (PlanPhaseMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func planPhaseUsageDiscount, + System::Func planPhaseAmountDiscount, + System::Func planPhasePercentageDiscount, + System::Func planPhaseMinimum, + System::Func planPhaseMaximum + ) + { + return this.Value switch + { + PlanPhaseUsageDiscountAdjustment value => planPhaseUsageDiscount(value), + PlanPhaseAmountDiscountAdjustment value => planPhaseAmountDiscount(value), + PlanPhasePercentageDiscountAdjustment value => planPhasePercentageDiscount(value), + PlanPhaseMinimumAdjustment value => planPhaseMinimum(value), + PlanPhaseMaximumAdjustment value => planPhaseMaximum(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Adjustment"), + }; + } + + public static implicit operator Adjustment(PlanPhaseUsageDiscountAdjustment value) => + new(value); + + public static implicit operator Adjustment(PlanPhaseAmountDiscountAdjustment value) => + new(value); + + public static implicit operator Adjustment(PlanPhasePercentageDiscountAdjustment value) => + new(value); + + public static implicit operator Adjustment(PlanPhaseMinimumAdjustment value) => new(value); + + public static implicit operator Adjustment(PlanPhaseMaximumAdjustment value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + this.Switch( + (planPhaseUsageDiscount) => planPhaseUsageDiscount.Validate(), + (planPhaseAmountDiscount) => planPhaseAmountDiscount.Validate(), + (planPhasePercentageDiscount) => planPhasePercentageDiscount.Validate(), + (planPhaseMinimum) => planPhaseMinimum.Validate(), + (planPhaseMaximum) => planPhaseMaximum.Validate() + ); + } + + public virtual bool Equals(Adjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentConverter : JsonConverter +{ + public override Adjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new Adjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + Adjustment value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/AdjustmentIntervalProperties/Adjustment.cs b/src/Orb/Models/AdjustmentIntervalProperties/Adjustment.cs deleted file mode 100644 index a58dae8b..00000000 --- a/src/Orb/Models/AdjustmentIntervalProperties/Adjustment.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AdjustmentVariants = Orb.Models.AdjustmentIntervalProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.AdjustmentIntervalProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::PlanPhaseUsageDiscountAdjustment Create( - Models::PlanPhaseUsageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseAmountDiscountAdjustment Create( - Models::PlanPhaseAmountDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhasePercentageDiscountAdjustment Create( - Models::PlanPhasePercentageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseMinimumAdjustment Create( - Models::PlanPhaseMinimumAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseMaximumAdjustment Create( - Models::PlanPhaseMaximumAdjustment value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/AdjustmentIntervalProperties/AdjustmentVariants/All.cs b/src/Orb/Models/AdjustmentIntervalProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 8fa8a008..00000000 --- a/src/Orb/Models/AdjustmentIntervalProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,120 +0,0 @@ -using AdjustmentIntervalProperties = Orb.Models.AdjustmentIntervalProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.AdjustmentIntervalProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhaseUsageDiscountAdjustment, - Models::PlanPhaseUsageDiscountAdjustment - >) -)] -public sealed record class PlanPhaseUsageDiscountAdjustment( - Models::PlanPhaseUsageDiscountAdjustment Value -) - : AdjustmentIntervalProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseUsageDiscountAdjustment From( - Models::PlanPhaseUsageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhaseAmountDiscountAdjustment, - Models::PlanPhaseAmountDiscountAdjustment - >) -)] -public sealed record class PlanPhaseAmountDiscountAdjustment( - Models::PlanPhaseAmountDiscountAdjustment Value -) - : AdjustmentIntervalProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseAmountDiscountAdjustment From( - Models::PlanPhaseAmountDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhasePercentageDiscountAdjustment, - Models::PlanPhasePercentageDiscountAdjustment - >) -)] -public sealed record class PlanPhasePercentageDiscountAdjustment( - Models::PlanPhasePercentageDiscountAdjustment Value -) - : AdjustmentIntervalProperties::Adjustment, - Orb::IVariant< - PlanPhasePercentageDiscountAdjustment, - Models::PlanPhasePercentageDiscountAdjustment - > -{ - public static PlanPhasePercentageDiscountAdjustment From( - Models::PlanPhasePercentageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PlanPhaseMinimumAdjustment(Models::PlanPhaseMinimumAdjustment Value) - : AdjustmentIntervalProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseMinimumAdjustment From(Models::PlanPhaseMinimumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PlanPhaseMaximumAdjustment(Models::PlanPhaseMaximumAdjustment Value) - : AdjustmentIntervalProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseMaximumAdjustment From(Models::PlanPhaseMaximumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/AggregatedCost.cs b/src/Orb/Models/AggregatedCost.cs index f44aca74..7493481b 100644 --- a/src/Orb/Models/AggregatedCost.cs +++ b/src/Orb/Models/AggregatedCost.cs @@ -1,29 +1,23 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AggregatedCost : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AggregatedCost : JsonModel { - public required Generic::List PerPriceCosts + public required IReadOnlyList PerPriceCosts { get { - if (!this.Properties.TryGetValue("per_price_costs", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_price_costs", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("per_price_costs"); + return JsonModel.GetNotNullClass>(this.RawData, "per_price_costs"); } - set { this.Properties["per_price_costs"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "per_price_costs", value); } } /// @@ -31,48 +25,20 @@ public sealed record class AggregatedCost : Orb::ModelBase, Orb::IFromRaw public required string Subtotal { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } } - public required System::DateTime TimeframeEnd + public required DateTimeOffset TimeframeEnd { - get - { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "timeframe_end"); } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } } - public required System::DateTime TimeframeStart + public required DateTimeOffset TimeframeStart { - get - { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "timeframe_start"); } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } } /// @@ -80,17 +46,11 @@ public required string Subtotal /// public required string Total { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } } + /// public override void Validate() { foreach (var item in this.PerPriceCosts) @@ -105,18 +65,32 @@ public override void Validate() public AggregatedCost() { } + public AggregatedCost(AggregatedCost aggregatedCost) + : base(aggregatedCost) { } + + public AggregatedCost(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AggregatedCost(Generic::Dictionary properties) + [SetsRequiredMembers] + AggregatedCost(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static AggregatedCost FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static AggregatedCost FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class AggregatedCostFromRaw : IFromRawJson +{ + /// + public AggregatedCost FromRawUnchecked(IReadOnlyDictionary rawData) => + AggregatedCost.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Alerts/Alert.cs b/src/Orb/Models/Alerts/Alert.cs index 9f822b2f..10e79c19 100644 --- a/src/Orb/Models/Alerts/Alert.cs +++ b/src/Orb/Models/Alerts/Alert.cs @@ -1,10 +1,10 @@ -using AlertProperties = Orb.Models.Alerts.AlertProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Alerts; @@ -13,43 +13,30 @@ namespace Orb.Models.Alerts; /// [Alerts within Orb](/product-catalog/configuring-alerts) monitor spending, usage, /// or credit balance and trigger webhooks when a threshold is exceeded. /// -/// Alerts created through the API can be scoped to either customers or subscriptions. +/// Alerts created through the API can be scoped to either customers or subscriptions. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Alert : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Alert : JsonModel { /// /// Also referred to as alert_id in this documentation. /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// The creation time of the resource in Orb. /// - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// @@ -57,35 +44,17 @@ public required string ID /// public required string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// The customer the alert applies to. /// - public required Models::CustomerMinified? Customer + public required CustomerMinified? Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } /// @@ -93,126 +62,74 @@ public required string? Currency /// public required bool Enabled { - get - { - if (!this.Properties.TryGetValue("enabled", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "enabled", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["enabled"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "enabled"); } + init { JsonModel.Set(this._rawData, "enabled", value); } } /// /// The metric the alert applies to. /// - public required AlertProperties::Metric? Metric + public required Metric? Metric { - get - { - if (!this.Properties.TryGetValue("metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["metric"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "metric"); } + init { JsonModel.Set(this._rawData, "metric", value); } } /// /// The plan the alert applies to. /// - public required AlertProperties::Plan? Plan + public required Plan? Plan { - get - { - if (!this.Properties.TryGetValue("plan", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("plan", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["plan"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "plan"); } + init { JsonModel.Set(this._rawData, "plan", value); } } /// /// The subscription the alert applies to. /// - public required Models::SubscriptionMinified? Subscription + public required SubscriptionMinified? Subscription { get { - if (!this.Properties.TryGetValue("subscription", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "subscription"); } - set { this.Properties["subscription"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "subscription", value); } } /// /// The thresholds that define the conditions under which the alert will be triggered. /// - public required Generic::List? Thresholds + public required IReadOnlyList? Thresholds { - get - { - if (!this.Properties.TryGetValue("thresholds", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "thresholds", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["thresholds"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass>(this.RawData, "thresholds"); } + init { JsonModel.Set(this._rawData, "thresholds", value); } } /// /// The type of alert. This must be a valid alert type. /// - public required AlertProperties::Type Type + public required ApiEnum Type { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "type"); } + init { JsonModel.Set(this._rawData, "type", value); } } /// /// The current status of the alert. This field is only present for credit balance alerts. /// - public Generic::List? BalanceAlertStatus + public IReadOnlyList? BalanceAlertStatus { get { - if (!this.Properties.TryGetValue("balance_alert_status", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.Properties["balance_alert_status"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawData, + "balance_alert_status" ); } + init { JsonModel.Set(this._rawData, "balance_alert_status", value); } } + /// public override void Validate() { _ = this.ID; @@ -236,16 +153,286 @@ public override void Validate() public Alert() { } + public Alert(Alert alert) + : base(alert) { } + + public Alert(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Alert(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Alert FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AlertFromRaw : IFromRawJson +{ + /// + public Alert FromRawUnchecked(IReadOnlyDictionary rawData) => + Alert.FromRawUnchecked(rawData); +} + +/// +/// The metric the alert applies to. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Metric : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + } + + public Metric() { } + + public Metric(Metric metric) + : base(metric) { } + + public Metric(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Metric(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Metric FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Metric(string id) + : this() + { + this.ID = id; + } +} + +class MetricFromRaw : IFromRawJson +{ + /// + public Metric FromRawUnchecked(IReadOnlyDictionary rawData) => + Metric.FromRawUnchecked(rawData); +} + +/// +/// The plan the alert applies to. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Plan : JsonModel +{ + public required string? ID + { + get { return JsonModel.GetNullableClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// An optional user-defined ID for this plan resource, used throughout the system + /// as an alias for this Plan. Use this field to identify a plan by an existing + /// identifier in your system. + /// + public required string? ExternalPlanID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_plan_id"); } + init { JsonModel.Set(this._rawData, "external_plan_id", value); } + } + + public required string? Name + { + get { return JsonModel.GetNullableClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required string PlanVersion + { + get { return JsonModel.GetNotNullClass(this.RawData, "plan_version"); } + init { JsonModel.Set(this._rawData, "plan_version", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.ExternalPlanID; + _ = this.Name; + _ = this.PlanVersion; + } + + public Plan() { } + + public Plan(Plan plan) + : base(plan) { } + + public Plan(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Plan(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Plan FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanFromRaw : IFromRawJson +{ + /// + public Plan FromRawUnchecked(IReadOnlyDictionary rawData) => + Plan.FromRawUnchecked(rawData); +} + +/// +/// The type of alert. This must be a valid alert type. +/// +[JsonConverter(typeof(AlertTypeConverter))] +public enum AlertType +{ + CreditBalanceDepleted, + CreditBalanceDropped, + CreditBalanceRecovered, + UsageExceeded, + CostExceeded, +} + +sealed class AlertTypeConverter : JsonConverter +{ + public override AlertType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "credit_balance_depleted" => AlertType.CreditBalanceDepleted, + "credit_balance_dropped" => AlertType.CreditBalanceDropped, + "credit_balance_recovered" => AlertType.CreditBalanceRecovered, + "usage_exceeded" => AlertType.UsageExceeded, + "cost_exceeded" => AlertType.CostExceeded, + _ => (AlertType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AlertType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AlertType.CreditBalanceDepleted => "credit_balance_depleted", + AlertType.CreditBalanceDropped => "credit_balance_dropped", + AlertType.CreditBalanceRecovered => "credit_balance_recovered", + AlertType.UsageExceeded => "usage_exceeded", + AlertType.CostExceeded => "cost_exceeded", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Alert status is used to determine if an alert is currently in-alert or not. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BalanceAlertStatus : JsonModel +{ + /// + /// Whether the alert is currently in-alert or not. + /// + public required bool InAlert + { + get { return JsonModel.GetNotNullStruct(this.RawData, "in_alert"); } + init { JsonModel.Set(this._rawData, "in_alert", value); } + } + + /// + /// The value of the threshold that defines the alert status. + /// + public required double ThresholdValue + { + get { return JsonModel.GetNotNullStruct(this.RawData, "threshold_value"); } + init { JsonModel.Set(this._rawData, "threshold_value", value); } + } + + /// + public override void Validate() + { + _ = this.InAlert; + _ = this.ThresholdValue; + } + + public BalanceAlertStatus() { } + + public BalanceAlertStatus(BalanceAlertStatus balanceAlertStatus) + : base(balanceAlertStatus) { } + + public BalanceAlertStatus(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Alert(Generic::Dictionary properties) + [SetsRequiredMembers] + BalanceAlertStatus(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Alert FromRawUnchecked(Generic::Dictionary properties) + /// + public static BalanceAlertStatus FromRawUnchecked( + IReadOnlyDictionary rawData + ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class BalanceAlertStatusFromRaw : IFromRawJson +{ + /// + public BalanceAlertStatus FromRawUnchecked(IReadOnlyDictionary rawData) => + BalanceAlertStatus.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Alerts/AlertCreateForCustomerParams.cs b/src/Orb/Models/Alerts/AlertCreateForCustomerParams.cs index be9efe1b..88149086 100644 --- a/src/Orb/Models/Alerts/AlertCreateForCustomerParams.cs +++ b/src/Orb/Models/Alerts/AlertCreateForCustomerParams.cs @@ -1,104 +1,190 @@ -using AlertCreateForCustomerParamsProperties = Orb.Models.Alerts.AlertCreateForCustomerParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Alerts; /// /// This endpoint creates a new alert to monitor a customer's credit balance. There /// are three types of alerts that can be scoped to customers: `credit_balance_depleted`, -/// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have -/// a maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). +/// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have a +/// maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). /// `credit_balance_dropped` alerts require a list of thresholds to be provided while /// `credit_balance_depleted` and `credit_balance_recovered` alerts do not require thresholds. /// -public sealed record class AlertCreateForCustomerParams : Orb::ParamsBase +public sealed record class AlertCreateForCustomerParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string CustomerID; + public string? CustomerID { get; init; } /// /// The case sensitive currency or custom pricing unit to use for this alert. /// public required string Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// /// The type of alert to create. This must be a valid alert type. /// - public required AlertCreateForCustomerParamsProperties::Type Type + public required ApiEnum Type { get { - if (!this.BodyProperties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "type" + ); } - set { this.BodyProperties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "type", value); } } /// /// The thresholds that define the values at which the alert will be triggered. /// - public Generic::List? Thresholds + public IReadOnlyList? Thresholds { - get - { - if (!this.BodyProperties.TryGetValue("thresholds", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass>(this.RawBodyData, "thresholds"); } + init { JsonModel.Set(this._rawBodyData, "thresholds", value); } + } - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.BodyProperties["thresholds"] = Json::JsonSerializer.SerializeToElement(value); } + public AlertCreateForCustomerParams() { } + + public AlertCreateForCustomerParams(AlertCreateForCustomerParams alertCreateForCustomerParams) + : base(alertCreateForCustomerParams) + { + this._rawBodyData = [.. alertCreateForCustomerParams._rawBodyData]; + } + + public AlertCreateForCustomerParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } - public override System::Uri Url(Orb::IOrbClient client) +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertCreateForCustomerParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static AlertCreateForCustomerParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/customer_id/{0}", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// The type of alert to create. This must be a valid alert type. +/// +[JsonConverter(typeof(global::Orb.Models.Alerts.TypeConverter))] +public enum Type +{ + CreditBalanceDepleted, + CreditBalanceDropped, + CreditBalanceRecovered, +} + +sealed class TypeConverter : JsonConverter +{ + public override global::Orb.Models.Alerts.Type Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "credit_balance_depleted" => global::Orb.Models.Alerts.Type.CreditBalanceDepleted, + "credit_balance_dropped" => global::Orb.Models.Alerts.Type.CreditBalanceDropped, + "credit_balance_recovered" => global::Orb.Models.Alerts.Type.CreditBalanceRecovered, + _ => (global::Orb.Models.Alerts.Type)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Alerts.Type value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Alerts.Type.CreditBalanceDepleted => "credit_balance_depleted", + global::Orb.Models.Alerts.Type.CreditBalanceDropped => "credit_balance_dropped", + global::Orb.Models.Alerts.Type.CreditBalanceRecovered => "credit_balance_recovered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Alerts/AlertCreateForCustomerParamsProperties/Type.cs b/src/Orb/Models/Alerts/AlertCreateForCustomerParamsProperties/Type.cs deleted file mode 100644 index 9509643a..00000000 --- a/src/Orb/Models/Alerts/AlertCreateForCustomerParamsProperties/Type.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertCreateForCustomerParamsProperties; - -/// -/// The type of alert to create. This must be a valid alert type. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type CreditBalanceDepleted = new("credit_balance_depleted"); - - public static readonly Type CreditBalanceDropped = new("credit_balance_dropped"); - - public static readonly Type CreditBalanceRecovered = new("credit_balance_recovered"); - - readonly string _value = value; - - public enum Value - { - CreditBalanceDepleted, - CreditBalanceDropped, - CreditBalanceRecovered, - } - - public Value Known() => - _value switch - { - "credit_balance_depleted" => Value.CreditBalanceDepleted, - "credit_balance_dropped" => Value.CreditBalanceDropped, - "credit_balance_recovered" => Value.CreditBalanceRecovered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParams.cs b/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParams.cs index 2c140857..6c04a44f 100644 --- a/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParams.cs +++ b/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParams.cs @@ -1,104 +1,198 @@ -using AlertCreateForExternalCustomerParamsProperties = Orb.Models.Alerts.AlertCreateForExternalCustomerParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Alerts; /// /// This endpoint creates a new alert to monitor a customer's credit balance. There /// are three types of alerts that can be scoped to customers: `credit_balance_depleted`, -/// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have -/// a maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). +/// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have a +/// maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). /// `credit_balance_dropped` alerts require a list of thresholds to be provided while /// `credit_balance_depleted` and `credit_balance_recovered` alerts do not require thresholds. /// -public sealed record class AlertCreateForExternalCustomerParams : Orb::ParamsBase +public sealed record class AlertCreateForExternalCustomerParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } /// /// The case sensitive currency or custom pricing unit to use for this alert. /// public required string Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// /// The type of alert to create. This must be a valid alert type. /// - public required AlertCreateForExternalCustomerParamsProperties::Type Type + public required ApiEnum Type { get { - if (!this.BodyProperties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawBodyData, "type"); } - set { this.BodyProperties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "type", value); } } /// /// The thresholds that define the values at which the alert will be triggered. /// - public Generic::List? Thresholds + public IReadOnlyList? Thresholds { - get - { - if (!this.BodyProperties.TryGetValue("thresholds", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass>(this.RawBodyData, "thresholds"); } + init { JsonModel.Set(this._rawBodyData, "thresholds", value); } + } - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.BodyProperties["thresholds"] = Json::JsonSerializer.SerializeToElement(value); } + public AlertCreateForExternalCustomerParams() { } + + public AlertCreateForExternalCustomerParams( + AlertCreateForExternalCustomerParams alertCreateForExternalCustomerParams + ) + : base(alertCreateForExternalCustomerParams) + { + this._rawBodyData = [.. alertCreateForExternalCustomerParams._rawBodyData]; + } + + public AlertCreateForExternalCustomerParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } - public override System::Uri Url(Orb::IOrbClient client) +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertCreateForExternalCustomerParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static AlertCreateForExternalCustomerParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/external_customer_id/{0}", this.ExternalCustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// The type of alert to create. This must be a valid alert type. +/// +[JsonConverter(typeof(AlertCreateForExternalCustomerParamsTypeConverter))] +public enum AlertCreateForExternalCustomerParamsType +{ + CreditBalanceDepleted, + CreditBalanceDropped, + CreditBalanceRecovered, +} + +sealed class AlertCreateForExternalCustomerParamsTypeConverter + : JsonConverter +{ + public override AlertCreateForExternalCustomerParamsType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "credit_balance_depleted" => + AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted, + "credit_balance_dropped" => + AlertCreateForExternalCustomerParamsType.CreditBalanceDropped, + "credit_balance_recovered" => + AlertCreateForExternalCustomerParamsType.CreditBalanceRecovered, + _ => (AlertCreateForExternalCustomerParamsType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AlertCreateForExternalCustomerParamsType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AlertCreateForExternalCustomerParamsType.CreditBalanceDepleted => + "credit_balance_depleted", + AlertCreateForExternalCustomerParamsType.CreditBalanceDropped => + "credit_balance_dropped", + AlertCreateForExternalCustomerParamsType.CreditBalanceRecovered => + "credit_balance_recovered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParamsProperties/Type.cs b/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParamsProperties/Type.cs deleted file mode 100644 index b5060f3e..00000000 --- a/src/Orb/Models/Alerts/AlertCreateForExternalCustomerParamsProperties/Type.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertCreateForExternalCustomerParamsProperties; - -/// -/// The type of alert to create. This must be a valid alert type. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type CreditBalanceDepleted = new("credit_balance_depleted"); - - public static readonly Type CreditBalanceDropped = new("credit_balance_dropped"); - - public static readonly Type CreditBalanceRecovered = new("credit_balance_recovered"); - - readonly string _value = value; - - public enum Value - { - CreditBalanceDepleted, - CreditBalanceDropped, - CreditBalanceRecovered, - } - - public Value Known() => - _value switch - { - "credit_balance_depleted" => Value.CreditBalanceDepleted, - "credit_balance_dropped" => Value.CreditBalanceDropped, - "credit_balance_recovered" => Value.CreditBalanceRecovered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Alerts/AlertCreateForSubscriptionParams.cs b/src/Orb/Models/Alerts/AlertCreateForSubscriptionParams.cs index 85a401b1..73da0218 100644 --- a/src/Orb/Models/Alerts/AlertCreateForSubscriptionParams.cs +++ b/src/Orb/Models/Alerts/AlertCreateForSubscriptionParams.cs @@ -1,66 +1,61 @@ -using AlertCreateForSubscriptionParamsProperties = Orb.Models.Alerts.AlertCreateForSubscriptionParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Alerts; /// /// This endpoint is used to create alerts at the subscription level. /// -/// Subscription level alerts can be one of two types: `usage_exceeded` or `cost_exceeded`. +/// Subscription level alerts can be one of two types: `usage_exceeded` or `cost_exceeded`. /// A `usage_exceeded` alert is scoped to a particular metric and is triggered when /// the usage of that metric exceeds predefined thresholds during the current billing -/// cycle. A `cost_exceeded` alert is triggered when the total amount due during -/// the current billing cycle surpasses predefined thresholds. `cost_exceeded` alerts +/// cycle. A `cost_exceeded` alert is triggered when the total amount due during the +/// current billing cycle surpasses predefined thresholds. `cost_exceeded` alerts /// do not include burndown of pre-purchase credits. Each subscription can have one /// `cost_exceeded` alert and one `usage_exceeded` alert per metric that is a part /// of the subscription. Alerts are triggered based on usage or cost conditions met -/// during the current billing cycle. +/// during the current billing cycle. /// -public sealed record class AlertCreateForSubscriptionParams : Orb::ParamsBase +public sealed record class AlertCreateForSubscriptionParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// The thresholds that define the values at which the alert will be triggered. /// - public required Generic::List Thresholds + public required IReadOnlyList Thresholds { - get - { - if (!this.BodyProperties.TryGetValue("thresholds", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "thresholds", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("thresholds"); - } - set { this.BodyProperties["thresholds"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawBodyData, "thresholds"); } + init { JsonModel.Set(this._rawBodyData, "thresholds", value); } } /// /// The type of alert to create. This must be a valid alert type. /// - public required AlertCreateForSubscriptionParamsProperties::Type Type + public required ApiEnum Type { get { - if (!this.BodyProperties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "type" + ); } - set { this.BodyProperties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "type", value); } } /// @@ -68,42 +63,133 @@ public sealed record class AlertCreateForSubscriptionParams : Orb::ParamsBase /// public string? MetricID { - get - { - if (!this.BodyProperties.TryGetValue("metric_id", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "metric_id"); } + init { JsonModel.Set(this._rawBodyData, "metric_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["metric_id"] = Json::JsonSerializer.SerializeToElement(value); } + public AlertCreateForSubscriptionParams() { } + + public AlertCreateForSubscriptionParams( + AlertCreateForSubscriptionParams alertCreateForSubscriptionParams + ) + : base(alertCreateForSubscriptionParams) + { + this._rawBodyData = [.. alertCreateForSubscriptionParams._rawBodyData]; + } + + public AlertCreateForSubscriptionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } - public override System::Uri Url(Orb::IOrbClient client) +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertCreateForSubscriptionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static AlertCreateForSubscriptionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/subscription_id/{0}", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// The type of alert to create. This must be a valid alert type. +/// +[JsonConverter(typeof(AlertCreateForSubscriptionParamsTypeConverter))] +public enum AlertCreateForSubscriptionParamsType +{ + UsageExceeded, + CostExceeded, +} + +sealed class AlertCreateForSubscriptionParamsTypeConverter + : JsonConverter +{ + public override AlertCreateForSubscriptionParamsType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_exceeded" => AlertCreateForSubscriptionParamsType.UsageExceeded, + "cost_exceeded" => AlertCreateForSubscriptionParamsType.CostExceeded, + _ => (AlertCreateForSubscriptionParamsType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AlertCreateForSubscriptionParamsType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AlertCreateForSubscriptionParamsType.UsageExceeded => "usage_exceeded", + AlertCreateForSubscriptionParamsType.CostExceeded => "cost_exceeded", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Alerts/AlertCreateForSubscriptionParamsProperties/Type.cs b/src/Orb/Models/Alerts/AlertCreateForSubscriptionParamsProperties/Type.cs deleted file mode 100644 index f231d73b..00000000 --- a/src/Orb/Models/Alerts/AlertCreateForSubscriptionParamsProperties/Type.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertCreateForSubscriptionParamsProperties; - -/// -/// The type of alert to create. This must be a valid alert type. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type UsageExceeded = new("usage_exceeded"); - - public static readonly Type CostExceeded = new("cost_exceeded"); - - readonly string _value = value; - - public enum Value - { - UsageExceeded, - CostExceeded, - } - - public Value Known() => - _value switch - { - "usage_exceeded" => Value.UsageExceeded, - "cost_exceeded" => Value.CostExceeded, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Alerts/AlertDisableParams.cs b/src/Orb/Models/Alerts/AlertDisableParams.cs index d8be8973..524ce922 100644 --- a/src/Orb/Models/Alerts/AlertDisableParams.cs +++ b/src/Orb/Models/Alerts/AlertDisableParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Alerts; @@ -10,47 +13,74 @@ namespace Orb.Models.Alerts; /// a specific subscription, you must include the `subscription_id`. The `subscription_id` /// is not required for customer or subscription level alerts. /// -public sealed record class AlertDisableParams : Orb::ParamsBase +public sealed record class AlertDisableParams : ParamsBase { - public required string AlertConfigurationID; + public string? AlertConfigurationID { get; init; } /// /// Used to update the status of a plan alert scoped to this subscription_id /// public string? SubscriptionID { - get - { - if (!this.QueryProperties.TryGetValue("subscription_id", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawQueryData, "subscription_id"); } + init { JsonModel.Set(this._rawQueryData, "subscription_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["subscription_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + public AlertDisableParams() { } + + public AlertDisableParams(AlertDisableParams alertDisableParams) + : base(alertDisableParams) { } + + public AlertDisableParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertDisableParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static AlertDisableParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/{0}/disable", this.AlertConfigurationID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Alerts/AlertEnableParams.cs b/src/Orb/Models/Alerts/AlertEnableParams.cs index 5278202b..7a4de77d 100644 --- a/src/Orb/Models/Alerts/AlertEnableParams.cs +++ b/src/Orb/Models/Alerts/AlertEnableParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Alerts; @@ -10,47 +13,74 @@ namespace Orb.Models.Alerts; /// a specific subscription, you must include the `subscription_id`. The `subscription_id` /// is not required for customer or subscription level alerts. /// -public sealed record class AlertEnableParams : Orb::ParamsBase +public sealed record class AlertEnableParams : ParamsBase { - public required string AlertConfigurationID; + public string? AlertConfigurationID { get; init; } /// /// Used to update the status of a plan alert scoped to this subscription_id /// public string? SubscriptionID { - get - { - if (!this.QueryProperties.TryGetValue("subscription_id", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawQueryData, "subscription_id"); } + init { JsonModel.Set(this._rawQueryData, "subscription_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["subscription_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + public AlertEnableParams() { } + + public AlertEnableParams(AlertEnableParams alertEnableParams) + : base(alertEnableParams) { } + + public AlertEnableParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertEnableParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static AlertEnableParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/{0}/enable", this.AlertConfigurationID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Alerts/AlertListPage.cs b/src/Orb/Models/Alerts/AlertListPage.cs new file mode 100644 index 00000000..a0121cf3 --- /dev/null +++ b/src/Orb/Models/Alerts/AlertListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Alerts; + +public sealed class AlertListPage( + IAlertService service, + AlertListParams parameters, + AlertListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Alerts/AlertListPageResponse.cs b/src/Orb/Models/Alerts/AlertListPageResponse.cs index c4f94958..581be560 100644 --- a/src/Orb/Models/Alerts/AlertListPageResponse.cs +++ b/src/Orb/Models/Alerts/AlertListPageResponse.cs @@ -1,50 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Alerts; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AlertListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AlertListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +40,35 @@ public override void Validate() public AlertListPageResponse() { } + public AlertListPageResponse(AlertListPageResponse alertListPageResponse) + : base(alertListPageResponse) { } + + public AlertListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AlertListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + AlertListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static AlertListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class AlertListPageResponseFromRaw : IFromRawJson +{ + /// + public AlertListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AlertListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Alerts/AlertListParams.cs b/src/Orb/Models/Alerts/AlertListParams.cs index bbb8d286..c90dc983 100644 --- a/src/Orb/Models/Alerts/AlertListParams.cs +++ b/src/Orb/Models/Alerts/AlertListParams.cs @@ -1,85 +1,67 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Alerts; /// /// This endpoint returns a list of alerts within Orb. /// -/// The request must specify one of `customer_id`, `external_customer_id`, or `subscription_id`. +/// The request must specify one of `customer_id`, `external_customer_id`, +/// or `subscription_id`. /// -/// If querying by subscripion_id, the endpoint will return the subscription level -/// alerts as well as the plan level alerts associated with the subscription. +/// If querying by subscription_id, the endpoint will return the subscription +/// level alerts as well as the plan level alerts associated with the subscription. /// -/// The list of alerts is ordered starting from the most recently created alert. -/// This endpoint follows Orb's [standardized pagination format](/api-reference/pagination). +/// The list of alerts is ordered starting from the most recently created alert. +/// This endpoint follows Orb's [standardized pagination format](/api-reference/pagination). /// -public sealed record class AlertListParams : Orb::ParamsBase +public sealed record class AlertListParams : ParamsBase { - public System::DateTime? CreatedAtGt + public DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[gt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[lt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -88,14 +70,8 @@ public sealed record class AlertListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -103,17 +79,8 @@ public string? Cursor /// public string? CustomerID { - get - { - if (!this.QueryProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "customer_id"); } + init { JsonModel.Set(this._rawQueryData, "customer_id", value); } } /// @@ -123,22 +90,9 @@ public string? ExternalCustomerID { get { - if ( - !this.QueryProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawQueryData, "external_customer_id"); } + init { JsonModel.Set(this._rawQueryData, "external_customer_id", value); } } /// @@ -146,14 +100,16 @@ public string? ExternalCustomerID /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } /// @@ -161,35 +117,62 @@ public long? Limit /// public string? SubscriptionID { - get - { - if (!this.QueryProperties.TryGetValue("subscription_id", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawQueryData, "subscription_id"); } + init { JsonModel.Set(this._rawQueryData, "subscription_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["subscription_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + public AlertListParams() { } + + public AlertListParams(AlertListParams alertListParams) + : base(alertListParams) { } + + public AlertListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static AlertListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/alerts") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/alerts") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Alerts/AlertProperties/BalanceAlertStatus.cs b/src/Orb/Models/Alerts/AlertProperties/BalanceAlertStatus.cs deleted file mode 100644 index 3715045e..00000000 --- a/src/Orb/Models/Alerts/AlertProperties/BalanceAlertStatus.cs +++ /dev/null @@ -1,74 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertProperties; - -/// -/// Alert status is used to determine if an alert is currently in-alert or not. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BalanceAlertStatus : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Whether the alert is currently in-alert or not. - /// - public required bool InAlert - { - get - { - if (!this.Properties.TryGetValue("in_alert", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "in_alert", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["in_alert"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The value of the threshold that defines the alert status. - /// - public required double ThresholdValue - { - get - { - if (!this.Properties.TryGetValue("threshold_value", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold_value", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["threshold_value"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.InAlert; - _ = this.ThresholdValue; - } - - public BalanceAlertStatus() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BalanceAlertStatus(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BalanceAlertStatus FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Alerts/AlertProperties/Metric.cs b/src/Orb/Models/Alerts/AlertProperties/Metric.cs deleted file mode 100644 index 1ed6a70f..00000000 --- a/src/Orb/Models/Alerts/AlertProperties/Metric.cs +++ /dev/null @@ -1,48 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertProperties; - -/// -/// The metric the alert applies to. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Metric : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - } - - public Metric() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Metric(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Metric FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Alerts/AlertProperties/Plan.cs b/src/Orb/Models/Alerts/AlertProperties/Plan.cs deleted file mode 100644 index 859ec429..00000000 --- a/src/Orb/Models/Alerts/AlertProperties/Plan.cs +++ /dev/null @@ -1,101 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertProperties; - -/// -/// The plan the alert applies to. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Plan : Orb::ModelBase, Orb::IFromRaw -{ - public required string? ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional user-defined ID for this plan resource, used throughout the system - /// as an alias for this Plan. Use this field to identify a plan by an existing - /// identifier in your system. - /// - public required string? ExternalPlanID - { - get - { - if (!this.Properties.TryGetValue("external_plan_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_plan_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_plan_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string? Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string PlanVersion - { - get - { - if (!this.Properties.TryGetValue("plan_version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_version", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("plan_version"); - } - set { this.Properties["plan_version"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.ExternalPlanID; - _ = this.Name; - _ = this.PlanVersion; - } - - public Plan() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Plan(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Plan FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Alerts/AlertProperties/Type.cs b/src/Orb/Models/Alerts/AlertProperties/Type.cs deleted file mode 100644 index b272650f..00000000 --- a/src/Orb/Models/Alerts/AlertProperties/Type.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Alerts.AlertProperties; - -/// -/// The type of alert. This must be a valid alert type. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type CreditBalanceDepleted = new("credit_balance_depleted"); - - public static readonly Type CreditBalanceDropped = new("credit_balance_dropped"); - - public static readonly Type CreditBalanceRecovered = new("credit_balance_recovered"); - - public static readonly Type UsageExceeded = new("usage_exceeded"); - - public static readonly Type CostExceeded = new("cost_exceeded"); - - readonly string _value = value; - - public enum Value - { - CreditBalanceDepleted, - CreditBalanceDropped, - CreditBalanceRecovered, - UsageExceeded, - CostExceeded, - } - - public Value Known() => - _value switch - { - "credit_balance_depleted" => Value.CreditBalanceDepleted, - "credit_balance_dropped" => Value.CreditBalanceDropped, - "credit_balance_recovered" => Value.CreditBalanceRecovered, - "usage_exceeded" => Value.UsageExceeded, - "cost_exceeded" => Value.CostExceeded, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Alerts/AlertRetrieveParams.cs b/src/Orb/Models/Alerts/AlertRetrieveParams.cs index 9f755da5..2147730c 100644 --- a/src/Orb/Models/Alerts/AlertRetrieveParams.cs +++ b/src/Orb/Models/Alerts/AlertRetrieveParams.cs @@ -1,32 +1,74 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Alerts; /// /// This endpoint retrieves an alert by its ID. /// -public sealed record class AlertRetrieveParams : Orb::ParamsBase +public sealed record class AlertRetrieveParams : ParamsBase { - public required string AlertID; + public string? AlertID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public AlertRetrieveParams() { } + + public AlertRetrieveParams(AlertRetrieveParams alertRetrieveParams) + : base(alertRetrieveParams) { } + + public AlertRetrieveParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertRetrieveParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static AlertRetrieveParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/{0}", this.AlertID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/{0}", this.AlertID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Alerts/AlertUpdateParams.cs b/src/Orb/Models/Alerts/AlertUpdateParams.cs index 596a12ac..698fad87 100644 --- a/src/Orb/Models/Alerts/AlertUpdateParams.cs +++ b/src/Orb/Models/Alerts/AlertUpdateParams.cs @@ -1,66 +1,109 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Alerts; /// /// This endpoint updates the thresholds of an alert. /// -public sealed record class AlertUpdateParams : Orb::ParamsBase +public sealed record class AlertUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string AlertConfigurationID; + public string? AlertConfigurationID { get; init; } /// /// The thresholds that define the values at which the alert will be triggered. /// - public required Generic::List Thresholds + public required IReadOnlyList Thresholds { - get - { - if (!this.BodyProperties.TryGetValue("thresholds", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "thresholds", - "Missing required argument" - ); + get { return JsonModel.GetNotNullClass>(this.RawBodyData, "thresholds"); } + init { JsonModel.Set(this._rawBodyData, "thresholds", value); } + } - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("thresholds"); - } - set { this.BodyProperties["thresholds"] = Json::JsonSerializer.SerializeToElement(value); } + public AlertUpdateParams() { } + + public AlertUpdateParams(AlertUpdateParams alertUpdateParams) + : base(alertUpdateParams) + { + this._rawBodyData = [.. alertUpdateParams._rawBodyData]; + } + + public AlertUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AlertUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static AlertUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/alerts/{0}", this.AlertConfigurationID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Alerts/Threshold.cs b/src/Orb/Models/Alerts/Threshold.cs index 7fcd76b6..9b172763 100644 --- a/src/Orb/Models/Alerts/Threshold.cs +++ b/src/Orb/Models/Alerts/Threshold.cs @@ -1,17 +1,17 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Alerts; /// /// Thresholds are used to define the conditions under which an alert will be triggered. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Threshold : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Threshold : JsonModel { /// /// The value at which an alert will fire. For credit balance alerts, the alert @@ -20,16 +20,11 @@ public sealed record class Threshold : Orb::ModelBase, Orb::IFromRaw /// public required double Value { - get - { - if (!this.Properties.TryGetValue("value", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("value", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["value"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "value"); } + init { JsonModel.Set(this._rawData, "value", value); } } + /// public override void Validate() { _ = this.Value; @@ -37,18 +32,39 @@ public override void Validate() public Threshold() { } + public Threshold(Threshold threshold) + : base(threshold) { } + + public Threshold(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Threshold(Generic::Dictionary properties) + [SetsRequiredMembers] + Threshold(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Threshold FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static Threshold FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Threshold(double value) + : this() { - return new(properties); + this.Value = value; } } + +class ThresholdFromRaw : IFromRawJson +{ + /// + public Threshold FromRawUnchecked(IReadOnlyDictionary rawData) => + Threshold.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Allocation.cs b/src/Orb/Models/Allocation.cs index 2db38d3b..d9e13f5d 100644 --- a/src/Orb/Models/Allocation.cs +++ b/src/Orb/Models/Allocation.cs @@ -1,85 +1,260 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Allocation : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Allocation : JsonModel { public required bool AllowsRollover { - get - { - if (!this.Properties.TryGetValue("allows_rollover", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "allows_rollover", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["allows_rollover"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "allows_rollover"); } + init { JsonModel.Set(this._rawData, "allows_rollover", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } public required CustomExpiration? CustomExpiration { get { - if (!this.Properties.TryGetValue("custom_expiration", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "custom_expiration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "custom_expiration"); } - set + init { JsonModel.Set(this._rawData, "custom_expiration", value); } + } + + public IReadOnlyList? Filters + { + get { return JsonModel.GetNullableClass>(this.RawData, "filters"); } + init { - this.Properties["custom_expiration"] = Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "filters", value); } } + /// public override void Validate() { _ = this.AllowsRollover; _ = this.Currency; this.CustomExpiration?.Validate(); + foreach (var item in this.Filters ?? []) + { + item.Validate(); + } } public Allocation() { } + public Allocation(Allocation allocation) + : base(allocation) { } + + public Allocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Allocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Allocation FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AllocationFromRaw : IFromRawJson +{ + /// + public Allocation FromRawUnchecked(IReadOnlyDictionary rawData) => + Allocation.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Filter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get { return JsonModel.GetNotNullClass>(this.RawData, "field"); } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public Filter() { } + + public Filter(Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Allocation(Generic::Dictionary properties) + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Allocation FromRawUnchecked( - Generic::Dictionary properties + /// + public static Filter FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public Filter FromRawUnchecked(IReadOnlyDictionary rawData) => + Filter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(FieldConverter))] +public enum Field +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class FieldConverter : JsonConverter +{ + public override Field Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => Field.PriceID, + "item_id" => Field.ItemID, + "price_type" => Field.PriceType, + "currency" => Field.Currency, + "pricing_unit_id" => Field.PricingUnitID, + _ => (Field)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Field value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Field.PriceID => "price_id", + Field.ItemID => "item_id", + Field.PriceType => "price_type", + Field.Currency => "currency", + Field.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(OperatorConverter))] +public enum Operator +{ + Includes, + Excludes, +} + +sealed class OperatorConverter : JsonConverter +{ + public override Operator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options ) { - return new(properties); + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => Operator.Includes, + "excludes" => Operator.Excludes, + _ => (Operator)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Operator value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Operator.Includes => "includes", + Operator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/AmountDiscount.cs b/src/Orb/Models/AmountDiscount.cs index 3910b904..b4c26adf 100644 --- a/src/Orb/Models/AmountDiscount.cs +++ b/src/Orb/Models/AmountDiscount.cs @@ -1,107 +1,75 @@ -using AmountDiscountProperties = Orb.Models.AmountDiscountProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AmountDiscount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AmountDiscount : JsonModel { /// /// Only available if discount_type is `amount`. /// - public required string AmountDiscount1 + public required string AmountDiscountValue { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_discount"); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } } - public required AmountDiscountProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// /// List of price_ids that this discount applies to. For plan/plan phase discounts, /// this can be a subset of prices. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this discount to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>(this.RawData, "filters"); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } public string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } + /// public override void Validate() { - _ = this.AmountDiscount1; + _ = this.AmountDiscountValue; this.DiscountType.Validate(); - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters ?? []) { item.Validate(); @@ -111,18 +79,261 @@ public override void Validate() public AmountDiscount() { } + public AmountDiscount(AmountDiscount amountDiscount) + : base(amountDiscount) { } + + public AmountDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AmountDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + AmountDiscount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static AmountDiscount FromRawUnchecked( - Generic::Dictionary properties + /// + public static AmountDiscount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AmountDiscountFromRaw : IFromRawJson +{ + /// + public AmountDiscount FromRawUnchecked(IReadOnlyDictionary rawData) => + AmountDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DiscountTypeConverter))] +public enum DiscountType +{ + Amount, +} + +sealed class DiscountTypeConverter : JsonConverter +{ + public override DiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "amount" => DiscountType.Amount, + _ => (DiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + DiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + DiscountType.Amount => "amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AmountDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public AmountDiscountFilter() { } + + public AmountDiscountFilter(AmountDiscountFilter amountDiscountFilter) + : base(amountDiscountFilter) { } + + public AmountDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AmountDiscountFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AmountDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AmountDiscountFilterFromRaw : IFromRawJson +{ + /// + public AmountDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AmountDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(AmountDiscountFilterFieldConverter))] +public enum AmountDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class AmountDiscountFilterFieldConverter : JsonConverter +{ + public override AmountDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => AmountDiscountFilterField.PriceID, + "item_id" => AmountDiscountFilterField.ItemID, + "price_type" => AmountDiscountFilterField.PriceType, + "currency" => AmountDiscountFilterField.Currency, + "pricing_unit_id" => AmountDiscountFilterField.PricingUnitID, + _ => (AmountDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmountDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AmountDiscountFilterField.PriceID => "price_id", + AmountDiscountFilterField.ItemID => "item_id", + AmountDiscountFilterField.PriceType => "price_type", + AmountDiscountFilterField.Currency => "currency", + AmountDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(AmountDiscountFilterOperatorConverter))] +public enum AmountDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class AmountDiscountFilterOperatorConverter : JsonConverter +{ + public override AmountDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => AmountDiscountFilterOperator.Includes, + "excludes" => AmountDiscountFilterOperator.Excludes, + _ => (AmountDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmountDiscountFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + AmountDiscountFilterOperator.Includes => "includes", + AmountDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/AmountDiscountInterval.cs b/src/Orb/Models/AmountDiscountInterval.cs index e0ab4325..97b883b2 100644 --- a/src/Orb/Models/AmountDiscountInterval.cs +++ b/src/Orb/Models/AmountDiscountInterval.cs @@ -1,144 +1,97 @@ -using AmountDiscountIntervalProperties = Orb.Models.AmountDiscountIntervalProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AmountDiscountInterval - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AmountDiscountInterval : JsonModel { /// /// Only available if discount_type is `amount`. /// public required string AmountDiscount { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_discount"); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } } /// /// The price interval ids that this discount interval applies to. /// - public required Generic::List AppliesToPriceIntervalIDs + public required IReadOnlyList AppliesToPriceIntervalIDs { get { - if ( - !this.Properties.TryGetValue( - "applies_to_price_interval_ids", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_interval_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_interval_ids"); - } - set - { - this.Properties["applies_to_price_interval_ids"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "applies_to_price_interval_ids" + ); } + init { JsonModel.Set(this._rawData, "applies_to_price_interval_ids", value); } } - public required AmountDiscountIntervalProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// /// The end date of the discount interval. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// /// The filters that determine which prices this discount interval applies to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// /// The start date of the discount interval. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { _ = this.AmountDiscount; - foreach (var item in this.AppliesToPriceIntervalIDs) - { - _ = item; - } + _ = this.AppliesToPriceIntervalIDs; this.DiscountType.Validate(); _ = this.EndDate; foreach (var item in this.Filters) @@ -150,18 +103,269 @@ public override void Validate() public AmountDiscountInterval() { } + public AmountDiscountInterval(AmountDiscountInterval amountDiscountInterval) + : base(amountDiscountInterval) { } + + public AmountDiscountInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AmountDiscountInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + AmountDiscountInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static AmountDiscountInterval FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AmountDiscountIntervalFromRaw : IFromRawJson +{ + /// + public AmountDiscountInterval FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AmountDiscountInterval.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(AmountDiscountIntervalDiscountTypeConverter))] +public enum AmountDiscountIntervalDiscountType +{ + Amount, +} + +sealed class AmountDiscountIntervalDiscountTypeConverter + : JsonConverter +{ + public override AmountDiscountIntervalDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "amount" => AmountDiscountIntervalDiscountType.Amount, + _ => (AmountDiscountIntervalDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmountDiscountIntervalDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AmountDiscountIntervalDiscountType.Amount => "amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class AmountDiscountIntervalFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public AmountDiscountIntervalFilter() { } + + public AmountDiscountIntervalFilter(AmountDiscountIntervalFilter amountDiscountIntervalFilter) + : base(amountDiscountIntervalFilter) { } + + public AmountDiscountIntervalFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AmountDiscountIntervalFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AmountDiscountIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AmountDiscountIntervalFilterFromRaw : IFromRawJson +{ + /// + public AmountDiscountIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AmountDiscountIntervalFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(AmountDiscountIntervalFilterFieldConverter))] +public enum AmountDiscountIntervalFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class AmountDiscountIntervalFilterFieldConverter + : JsonConverter +{ + public override AmountDiscountIntervalFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => AmountDiscountIntervalFilterField.PriceID, + "item_id" => AmountDiscountIntervalFilterField.ItemID, + "price_type" => AmountDiscountIntervalFilterField.PriceType, + "currency" => AmountDiscountIntervalFilterField.Currency, + "pricing_unit_id" => AmountDiscountIntervalFilterField.PricingUnitID, + _ => (AmountDiscountIntervalFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmountDiscountIntervalFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AmountDiscountIntervalFilterField.PriceID => "price_id", + AmountDiscountIntervalFilterField.ItemID => "item_id", + AmountDiscountIntervalFilterField.PriceType => "price_type", + AmountDiscountIntervalFilterField.Currency => "currency", + AmountDiscountIntervalFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(AmountDiscountIntervalFilterOperatorConverter))] +public enum AmountDiscountIntervalFilterOperator +{ + Includes, + Excludes, +} + +sealed class AmountDiscountIntervalFilterOperatorConverter + : JsonConverter +{ + public override AmountDiscountIntervalFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => AmountDiscountIntervalFilterOperator.Includes, + "excludes" => AmountDiscountIntervalFilterOperator.Excludes, + _ => (AmountDiscountIntervalFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmountDiscountIntervalFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + AmountDiscountIntervalFilterOperator.Includes => "includes", + AmountDiscountIntervalFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/AmountDiscountIntervalProperties/DiscountType.cs b/src/Orb/Models/AmountDiscountIntervalProperties/DiscountType.cs deleted file mode 100644 index 65601168..00000000 --- a/src/Orb/Models/AmountDiscountIntervalProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.AmountDiscountIntervalProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Amount = new("amount"); - - readonly string _value = value; - - public enum Value - { - Amount, - } - - public Value Known() => - _value switch - { - "amount" => Value.Amount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/AmountDiscountProperties/DiscountType.cs b/src/Orb/Models/AmountDiscountProperties/DiscountType.cs deleted file mode 100644 index ed2b3e6c..00000000 --- a/src/Orb/Models/AmountDiscountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.AmountDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Amount = new("amount"); - - readonly string _value = value; - - public enum Value - { - Amount, - } - - public Value Known() => - _value switch - { - "amount" => Value.Amount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/BPSConfig.cs b/src/Orb/Models/BPSConfig.cs deleted file mode 100644 index ce163f48..00000000 --- a/src/Orb/Models/BPSConfig.cs +++ /dev/null @@ -1,68 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BPSConfig : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Basis point take rate per event - /// - public required double BPS - { - get - { - if (!this.Properties.TryGetValue("bps", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("bps", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["bps"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional currency amount maximum to cap spend per event - /// - public string? PerUnitMaximum - { - get - { - if (!this.Properties.TryGetValue("per_unit_maximum", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_maximum"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.BPS; - _ = this.PerUnitMaximum; - } - - public BPSConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BPSConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BPSConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/BPSTier.cs b/src/Orb/Models/BPSTier.cs deleted file mode 100644 index d9707ff5..00000000 --- a/src/Orb/Models/BPSTier.cs +++ /dev/null @@ -1,104 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BPSTier : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Per-event basis point rate - /// - public required double BPS - { - get - { - if (!this.Properties.TryGetValue("bps", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("bps", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["bps"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Exclusive tier starting value - /// - public required string MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("minimum_amount"); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Inclusive tier ending value - /// - public string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Per unit maximum to charge - /// - public string? PerUnitMaximum - { - get - { - if (!this.Properties.TryGetValue("per_unit_maximum", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_maximum"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.BPS; - _ = this.MinimumAmount; - _ = this.MaximumAmount; - _ = this.PerUnitMaximum; - } - - public BPSTier() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BPSTier(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BPSTier FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParams.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParams.cs index 8652a016..e9f0f2a3 100644 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParams.cs +++ b/src/Orb/Models/Beta/BetaCreatePlanVersionParams.cs @@ -1,218 +1,16028 @@ -using BetaCreatePlanVersionParamsProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Beta; /// -/// This API endpoint is in beta and its interface may change. It is recommended for -/// use only in test mode. -/// /// This endpoint allows the creation of a new plan version for an existing plan. /// -public sealed record class BetaCreatePlanVersionParams : Orb::ParamsBase +public sealed record class BetaCreatePlanVersionParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string PlanID; + public string? PlanID { get; init; } /// /// New version number. /// public required long Version { - get - { - if (!this.BodyProperties.TryGetValue("version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "version", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["version"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "version"); } + init { JsonModel.Set(this._rawBodyData, "version", value); } } /// /// Additional adjustments to be added to the plan. /// - public Generic::List? AddAdjustments + public IReadOnlyList? AddAdjustments { get { - if (!this.BodyProperties.TryGetValue("add_adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "add_adjustments" ); } - set - { - this.BodyProperties["add_adjustments"] = Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawBodyData, "add_adjustments", value); } } /// /// Additional prices to be added to the plan. /// - public Generic::List? AddPrices + public IReadOnlyList? AddPrices + { + get { return JsonModel.GetNullableClass>(this.RawBodyData, "add_prices"); } + init { JsonModel.Set(this._rawBodyData, "add_prices", value); } + } + + /// + /// Adjustments to be removed from the plan. + /// + public IReadOnlyList? RemoveAdjustments { get { - if (!this.BodyProperties.TryGetValue("add_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "remove_adjustments" ); } - set { this.BodyProperties["add_prices"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "remove_adjustments", value); } } /// - /// Adjustments to be removed from the plan. + /// Prices to be removed from the plan. /// - public Generic::List? RemoveAdjustments + public IReadOnlyList? RemovePrices { get { - if ( - !this.BodyProperties.TryGetValue( - "remove_adjustments", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); + return JsonModel.GetNullableClass>(this.RawBodyData, "remove_prices"); } - set + init { JsonModel.Set(this._rawBodyData, "remove_prices", value); } + } + + /// + /// Adjustments to be replaced with additional adjustments on the plan. + /// + public IReadOnlyList? ReplaceAdjustments + { + get { - this.BodyProperties["remove_adjustments"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "replace_adjustments" ); } + init { JsonModel.Set(this._rawBodyData, "replace_adjustments", value); } } /// - /// Prices to be removed from the plan. + /// Prices to be replaced with additional prices on the plan. /// - public Generic::List? RemovePrices + public IReadOnlyList? ReplacePrices { get { - if (!this.BodyProperties.TryGetValue("remove_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "replace_prices" ); } - set + init { JsonModel.Set(this._rawBodyData, "replace_prices", value); } + } + + /// + /// Set this new plan version as the default + /// + public bool? SetAsDefault + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "set_as_default"); } + init { JsonModel.Set(this._rawBodyData, "set_as_default", value); } + } + + public BetaCreatePlanVersionParams() { } + + public BetaCreatePlanVersionParams(BetaCreatePlanVersionParams betaCreatePlanVersionParams) + : base(betaCreatePlanVersionParams) + { + this._rawBodyData = [.. betaCreatePlanVersionParams._rawBodyData]; + } + + public BetaCreatePlanVersionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BetaCreatePlanVersionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static BetaCreatePlanVersionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format("/plans/{0}/versions", this.PlanID) + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - this.BodyProperties["remove_prices"] = Json::JsonSerializer.SerializeToElement(value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } +} +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AddAdjustment : JsonModel +{ /// - /// Adjustments to be replaced with additional adjustments on the plan. + /// The definition of a new adjustment to create and add to the plan. /// - public Generic::List? ReplaceAdjustments + public required global::Orb.Models.Beta.Adjustment Adjustment { get { - if ( - !this.BodyProperties.TryGetValue( - "replace_adjustments", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" + ); + } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The phase to add this adjustment to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.PlanPhaseOrder; + } + + public AddAdjustment() { } + + public AddAdjustment(AddAdjustment addAdjustment) + : base(addAdjustment) { } + + public AddAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AddAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AddAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } - return Json::JsonSerializer.Deserialize?>( - element + [SetsRequiredMembers] + public AddAdjustment(global::Orb.Models.Beta.Adjustment adjustment) + : this() + { + this.Adjustment = adjustment; + } +} + +class AddAdjustmentFromRaw : IFromRawJson +{ + /// + public AddAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + AddAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the plan. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.AdjustmentConverter))] +public record class Adjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency ); } - set + } + + public bool? IsInvoiceLevel + { + get { - this.BodyProperties["replace_adjustments"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel ); } } + public Adjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + } + /// - /// Prices to be replaced with additional prices on the plan. + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// /// - public Generic::List? ReplacePrices + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) { - get + return this.Value switch { - if (!this.BodyProperties.TryGetValue("replace_prices", out Json::JsonElement element)) - return null; + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Adjustment"), + }; + } - return Json::JsonSerializer.Deserialize?>( - element - ); + public static implicit operator global::Orb.Models.Beta.Adjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Adjustment(NewUsageDiscount value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Adjustment(NewAmountDiscount value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Adjustment(NewMinimum value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Adjustment(NewMaximum value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Beta.Adjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentConverter : JsonConverter +{ + public override global::Orb.Models.Beta.Adjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); } - set + catch { - this.BodyProperties["replace_prices"] = Json::JsonSerializer.SerializeToElement(value); + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.Adjustment(element); + } } } + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.Adjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AddPrice : JsonModel +{ /// - /// Set this new plan version as the default + /// The allocation price to add to the plan. /// - public bool? SetAsDefault + public NewAllocationPrice? AllocationPrice { get { - if (!this.BodyProperties.TryGetValue("set_as_default", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); } - set + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// The phase to add this price to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New plan price request body params. + /// + public global::Orb.Models.Beta.Price? Price + { + get { - this.BodyProperties["set_as_default"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } } - public override System::Uri Url(Orb::IOrbClient client) + /// + public override void Validate() { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') - + string.Format("/plans/{0}/versions", this.PlanID) - ) - { - Query = this.QueryString(client), - }.Uri; + this.AllocationPrice?.Validate(); + _ = this.PlanPhaseOrder; + this.Price?.Validate(); } - public Http::StringContent BodyContent() + public AddPrice() { } + + public AddPrice(AddPrice addPrice) + : base(addPrice) { } + + public AddPrice(IReadOnlyDictionary rawData) { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AddPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AddPrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AddPriceFromRaw : IFromRawJson +{ + /// + public AddPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + AddPrice.FromRawUnchecked(rawData); +} + +/// +/// New plan price request body params. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.PriceConverter))] +public record class Price +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public string ItemID { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + newPlanUnit: (x) => x.ItemID, + newPlanTiered: (x) => x.ItemID, + newPlanBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newPlanPackage: (x) => x.ItemID, + newPlanMatrix: (x) => x.ItemID, + newPlanThresholdTotalAmount: (x) => x.ItemID, + newPlanTieredPackage: (x) => x.ItemID, + newPlanTieredWithMinimum: (x) => x.ItemID, + newPlanGroupedTiered: (x) => x.ItemID, + newPlanTieredPackageWithMinimum: (x) => x.ItemID, + newPlanPackageWithAllocation: (x) => x.ItemID, + newPlanUnitWithPercent: (x) => x.ItemID, + newPlanMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newPlanUnitWithProration: (x) => x.ItemID, + newPlanGroupedAllocation: (x) => x.ItemID, + newPlanBulkWithProration: (x) => x.ItemID, + newPlanGroupedWithProratedMinimum: (x) => x.ItemID, + newPlanGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newPlanMatrixWithDisplayName: (x) => x.ItemID, + newPlanGroupedTieredPackage: (x) => x.ItemID, + newPlanMaxGroupTieredPackage: (x) => x.ItemID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ItemID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ItemID, + newPlanCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newPlanMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); } } + + public string Name + { + get + { + return Match( + newPlanUnit: (x) => x.Name, + newPlanTiered: (x) => x.Name, + newPlanBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newPlanPackage: (x) => x.Name, + newPlanMatrix: (x) => x.Name, + newPlanThresholdTotalAmount: (x) => x.Name, + newPlanTieredPackage: (x) => x.Name, + newPlanTieredWithMinimum: (x) => x.Name, + newPlanGroupedTiered: (x) => x.Name, + newPlanTieredPackageWithMinimum: (x) => x.Name, + newPlanPackageWithAllocation: (x) => x.Name, + newPlanUnitWithPercent: (x) => x.Name, + newPlanMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newPlanUnitWithProration: (x) => x.Name, + newPlanGroupedAllocation: (x) => x.Name, + newPlanBulkWithProration: (x) => x.Name, + newPlanGroupedWithProratedMinimum: (x) => x.Name, + newPlanGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newPlanMatrixWithDisplayName: (x) => x.Name, + newPlanGroupedTieredPackage: (x) => x.Name, + newPlanMaxGroupTieredPackage: (x) => x.Name, + newPlanScalableMatrixWithUnitPricing: (x) => x.Name, + newPlanScalableMatrixWithTieredPricing: (x) => x.Name, + newPlanCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newPlanMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newPlanUnit: (x) => x.BillableMetricID, + newPlanTiered: (x) => x.BillableMetricID, + newPlanBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newPlanPackage: (x) => x.BillableMetricID, + newPlanMatrix: (x) => x.BillableMetricID, + newPlanThresholdTotalAmount: (x) => x.BillableMetricID, + newPlanTieredPackage: (x) => x.BillableMetricID, + newPlanTieredWithMinimum: (x) => x.BillableMetricID, + newPlanGroupedTiered: (x) => x.BillableMetricID, + newPlanTieredPackageWithMinimum: (x) => x.BillableMetricID, + newPlanPackageWithAllocation: (x) => x.BillableMetricID, + newPlanUnitWithPercent: (x) => x.BillableMetricID, + newPlanMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newPlanUnitWithProration: (x) => x.BillableMetricID, + newPlanGroupedAllocation: (x) => x.BillableMetricID, + newPlanBulkWithProration: (x) => x.BillableMetricID, + newPlanGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newPlanGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newPlanMatrixWithDisplayName: (x) => x.BillableMetricID, + newPlanGroupedTieredPackage: (x) => x.BillableMetricID, + newPlanMaxGroupTieredPackage: (x) => x.BillableMetricID, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newPlanCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newPlanMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newPlanUnit: (x) => x.BilledInAdvance, + newPlanTiered: (x) => x.BilledInAdvance, + newPlanBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newPlanPackage: (x) => x.BilledInAdvance, + newPlanMatrix: (x) => x.BilledInAdvance, + newPlanThresholdTotalAmount: (x) => x.BilledInAdvance, + newPlanTieredPackage: (x) => x.BilledInAdvance, + newPlanTieredWithMinimum: (x) => x.BilledInAdvance, + newPlanGroupedTiered: (x) => x.BilledInAdvance, + newPlanTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newPlanPackageWithAllocation: (x) => x.BilledInAdvance, + newPlanUnitWithPercent: (x) => x.BilledInAdvance, + newPlanMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newPlanUnitWithProration: (x) => x.BilledInAdvance, + newPlanGroupedAllocation: (x) => x.BilledInAdvance, + newPlanBulkWithProration: (x) => x.BilledInAdvance, + newPlanGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newPlanGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newPlanMatrixWithDisplayName: (x) => x.BilledInAdvance, + newPlanGroupedTieredPackage: (x) => x.BilledInAdvance, + newPlanMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newPlanCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newPlanMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.BillingCycleConfiguration, + newPlanTiered: (x) => x.BillingCycleConfiguration, + newPlanBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newPlanPackage: (x) => x.BillingCycleConfiguration, + newPlanMatrix: (x) => x.BillingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newPlanTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedTiered: (x) => x.BillingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newPlanUnitWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanBulkWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newPlanUnit: (x) => x.ConversionRate, + newPlanTiered: (x) => x.ConversionRate, + newPlanBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newPlanPackage: (x) => x.ConversionRate, + newPlanMatrix: (x) => x.ConversionRate, + newPlanThresholdTotalAmount: (x) => x.ConversionRate, + newPlanTieredPackage: (x) => x.ConversionRate, + newPlanTieredWithMinimum: (x) => x.ConversionRate, + newPlanGroupedTiered: (x) => x.ConversionRate, + newPlanTieredPackageWithMinimum: (x) => x.ConversionRate, + newPlanPackageWithAllocation: (x) => x.ConversionRate, + newPlanUnitWithPercent: (x) => x.ConversionRate, + newPlanMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newPlanUnitWithProration: (x) => x.ConversionRate, + newPlanGroupedAllocation: (x) => x.ConversionRate, + newPlanBulkWithProration: (x) => x.ConversionRate, + newPlanGroupedWithProratedMinimum: (x) => x.ConversionRate, + newPlanGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newPlanMatrixWithDisplayName: (x) => x.ConversionRate, + newPlanGroupedTieredPackage: (x) => x.ConversionRate, + newPlanMaxGroupTieredPackage: (x) => x.ConversionRate, + newPlanScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newPlanScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newPlanCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newPlanMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newPlanUnit: (x) => x.Currency, + newPlanTiered: (x) => x.Currency, + newPlanBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newPlanPackage: (x) => x.Currency, + newPlanMatrix: (x) => x.Currency, + newPlanThresholdTotalAmount: (x) => x.Currency, + newPlanTieredPackage: (x) => x.Currency, + newPlanTieredWithMinimum: (x) => x.Currency, + newPlanGroupedTiered: (x) => x.Currency, + newPlanTieredPackageWithMinimum: (x) => x.Currency, + newPlanPackageWithAllocation: (x) => x.Currency, + newPlanUnitWithPercent: (x) => x.Currency, + newPlanMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newPlanUnitWithProration: (x) => x.Currency, + newPlanGroupedAllocation: (x) => x.Currency, + newPlanBulkWithProration: (x) => x.Currency, + newPlanGroupedWithProratedMinimum: (x) => x.Currency, + newPlanGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newPlanMatrixWithDisplayName: (x) => x.Currency, + newPlanGroupedTieredPackage: (x) => x.Currency, + newPlanMaxGroupTieredPackage: (x) => x.Currency, + newPlanScalableMatrixWithUnitPricing: (x) => x.Currency, + newPlanScalableMatrixWithTieredPricing: (x) => x.Currency, + newPlanCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newPlanMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.DimensionalPriceConfiguration, + newPlanTiered: (x) => x.DimensionalPriceConfiguration, + newPlanBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newPlanPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMatrix: (x) => x.DimensionalPriceConfiguration, + newPlanThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newPlanUnit: (x) => x.ExternalPriceID, + newPlanTiered: (x) => x.ExternalPriceID, + newPlanBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newPlanPackage: (x) => x.ExternalPriceID, + newPlanMatrix: (x) => x.ExternalPriceID, + newPlanThresholdTotalAmount: (x) => x.ExternalPriceID, + newPlanTieredPackage: (x) => x.ExternalPriceID, + newPlanTieredWithMinimum: (x) => x.ExternalPriceID, + newPlanGroupedTiered: (x) => x.ExternalPriceID, + newPlanTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newPlanPackageWithAllocation: (x) => x.ExternalPriceID, + newPlanUnitWithPercent: (x) => x.ExternalPriceID, + newPlanMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newPlanUnitWithProration: (x) => x.ExternalPriceID, + newPlanGroupedAllocation: (x) => x.ExternalPriceID, + newPlanBulkWithProration: (x) => x.ExternalPriceID, + newPlanGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newPlanMatrixWithDisplayName: (x) => x.ExternalPriceID, + newPlanGroupedTieredPackage: (x) => x.ExternalPriceID, + newPlanMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newPlanCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newPlanMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newPlanUnit: (x) => x.FixedPriceQuantity, + newPlanTiered: (x) => x.FixedPriceQuantity, + newPlanBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newPlanPackage: (x) => x.FixedPriceQuantity, + newPlanMatrix: (x) => x.FixedPriceQuantity, + newPlanThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newPlanTieredPackage: (x) => x.FixedPriceQuantity, + newPlanTieredWithMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedTiered: (x) => x.FixedPriceQuantity, + newPlanTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newPlanPackageWithAllocation: (x) => x.FixedPriceQuantity, + newPlanUnitWithPercent: (x) => x.FixedPriceQuantity, + newPlanMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newPlanUnitWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanBulkWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newPlanMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newPlanGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newPlanMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newPlanCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newPlanUnit: (x) => x.InvoiceGroupingKey, + newPlanTiered: (x) => x.InvoiceGroupingKey, + newPlanBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newPlanPackage: (x) => x.InvoiceGroupingKey, + newPlanMatrix: (x) => x.InvoiceGroupingKey, + newPlanThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newPlanTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedTiered: (x) => x.InvoiceGroupingKey, + newPlanTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newPlanUnitWithPercent: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newPlanUnitWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanBulkWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newPlanGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newPlanCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.InvoicingCycleConfiguration, + newPlanTiered: (x) => x.InvoicingCycleConfiguration, + newPlanBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newPlanPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMatrix: (x) => x.InvoicingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newPlanUnit: (x) => x.ReferenceID, + newPlanTiered: (x) => x.ReferenceID, + newPlanBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newPlanPackage: (x) => x.ReferenceID, + newPlanMatrix: (x) => x.ReferenceID, + newPlanThresholdTotalAmount: (x) => x.ReferenceID, + newPlanTieredPackage: (x) => x.ReferenceID, + newPlanTieredWithMinimum: (x) => x.ReferenceID, + newPlanGroupedTiered: (x) => x.ReferenceID, + newPlanTieredPackageWithMinimum: (x) => x.ReferenceID, + newPlanPackageWithAllocation: (x) => x.ReferenceID, + newPlanUnitWithPercent: (x) => x.ReferenceID, + newPlanMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newPlanUnitWithProration: (x) => x.ReferenceID, + newPlanGroupedAllocation: (x) => x.ReferenceID, + newPlanBulkWithProration: (x) => x.ReferenceID, + newPlanGroupedWithProratedMinimum: (x) => x.ReferenceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newPlanMatrixWithDisplayName: (x) => x.ReferenceID, + newPlanGroupedTieredPackage: (x) => x.ReferenceID, + newPlanMaxGroupTieredPackage: (x) => x.ReferenceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newPlanCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newPlanMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public Price(NewPlanUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Beta.BulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Beta.TieredWithProration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.GroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanScalableMatrixWithUnitPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanScalableMatrixWithTieredPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.CumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Beta.Percent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Beta.EventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnit(out var value)) { + /// // `value` is of type `NewPlanUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnit([NotNullWhen(true)] out NewPlanUnitPrice? value) + { + value = this.Value as NewPlanUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTiered(out var value)) { + /// // `value` is of type `NewPlanTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTiered([NotNullWhen(true)] out NewPlanTieredPrice? value) + { + value = this.Value as NewPlanTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulk(out var value)) { + /// // `value` is of type `NewPlanBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulk([NotNullWhen(true)] out NewPlanBulkPrice? value) + { + value = this.Value as NewPlanBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.BulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out global::Orb.Models.Beta.BulkWithFilters? value + ) + { + value = this.Value as global::Orb.Models.Beta.BulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackage(out var value)) { + /// // `value` is of type `NewPlanPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackage([NotNullWhen(true)] out NewPlanPackagePrice? value) + { + value = this.Value as NewPlanPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrix(out var value)) { + /// // `value` is of type `NewPlanMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrix([NotNullWhen(true)] out NewPlanMatrixPrice? value) + { + value = this.Value as NewPlanMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewPlanThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanThresholdTotalAmount( + [NotNullWhen(true)] out NewPlanThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewPlanThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackage(out var value)) { + /// // `value` is of type `NewPlanTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackage( + [NotNullWhen(true)] out NewPlanTieredPackagePrice? value + ) + { + value = this.Value as NewPlanTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredWithMinimum( + [NotNullWhen(true)] out NewPlanTieredWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTiered(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTiered( + [NotNullWhen(true)] out NewPlanGroupedTieredPrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackageWithMinimum( + [NotNullWhen(true)] out NewPlanTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackageWithAllocation(out var value)) { + /// // `value` is of type `NewPlanPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackageWithAllocation( + [NotNullWhen(true)] out NewPlanPackageWithAllocationPrice? value + ) + { + value = this.Value as NewPlanPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithPercent(out var value)) { + /// // `value` is of type `NewPlanUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithPercent( + [NotNullWhen(true)] out NewPlanUnitWithPercentPrice? value + ) + { + value = this.Value as NewPlanUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewPlanMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithAllocation( + [NotNullWhen(true)] out NewPlanMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewPlanMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.TieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] out global::Orb.Models.Beta.TieredWithProration? value + ) + { + value = this.Value as global::Orb.Models.Beta.TieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithProration(out var value)) { + /// // `value` is of type `NewPlanUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithProration( + [NotNullWhen(true)] out NewPlanUnitWithProrationPrice? value + ) + { + value = this.Value as NewPlanUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedAllocation(out var value)) { + /// // `value` is of type `NewPlanGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedAllocation( + [NotNullWhen(true)] out NewPlanGroupedAllocationPrice? value + ) + { + value = this.Value as NewPlanGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulkWithProration(out var value)) { + /// // `value` is of type `NewPlanBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulkWithProration( + [NotNullWhen(true)] out NewPlanBulkWithProrationPrice? value + ) + { + value = this.Value as NewPlanBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.GroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out global::Orb.Models.Beta.GroupedWithMinMaxThresholds? value + ) + { + value = this.Value as global::Orb.Models.Beta.GroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewPlanMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithDisplayName( + [NotNullWhen(true)] out NewPlanMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewPlanMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTieredPackage( + [NotNullWhen(true)] out NewPlanGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewPlanMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMaxGroupTieredPackage( + [NotNullWhen(true)] out NewPlanMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewPlanMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewPlanCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanCumulativeGroupedBulk( + [NotNullWhen(true)] out NewPlanCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewPlanCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.CumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out global::Orb.Models.Beta.CumulativeGroupedAllocation? value + ) + { + value = this.Value as global::Orb.Models.Beta.CumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMinimumComposite(out var value)) { + /// // `value` is of type `NewPlanMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMinimumComposite( + [NotNullWhen(true)] out NewPlanMinimumCompositePrice? value + ) + { + value = this.Value as NewPlanMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.Percent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out global::Orb.Models.Beta.Percent? value) + { + value = this.Value as global::Orb.Models.Beta.Percent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.EventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] out global::Orb.Models.Beta.EventOutput? value + ) + { + value = this.Value as global::Orb.Models.Beta.EventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.BulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Beta.TieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Beta.GroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.CumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Beta.Percent value) => {...}, + /// (global::Orb.Models.Beta.EventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPlanUnit, + System::Action newPlanTiered, + System::Action newPlanBulk, + System::Action bulkWithFilters, + System::Action newPlanPackage, + System::Action newPlanMatrix, + System::Action newPlanThresholdTotalAmount, + System::Action newPlanTieredPackage, + System::Action newPlanTieredWithMinimum, + System::Action newPlanGroupedTiered, + System::Action newPlanTieredPackageWithMinimum, + System::Action newPlanPackageWithAllocation, + System::Action newPlanUnitWithPercent, + System::Action newPlanMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newPlanUnitWithProration, + System::Action newPlanGroupedAllocation, + System::Action newPlanBulkWithProration, + System::Action newPlanGroupedWithProratedMinimum, + System::Action newPlanGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newPlanMatrixWithDisplayName, + System::Action newPlanGroupedTieredPackage, + System::Action newPlanMaxGroupTieredPackage, + System::Action newPlanScalableMatrixWithUnitPricing, + System::Action newPlanScalableMatrixWithTieredPricing, + System::Action newPlanCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newPlanMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewPlanUnitPrice value: + newPlanUnit(value); + break; + case NewPlanTieredPrice value: + newPlanTiered(value); + break; + case NewPlanBulkPrice value: + newPlanBulk(value); + break; + case global::Orb.Models.Beta.BulkWithFilters value: + bulkWithFilters(value); + break; + case NewPlanPackagePrice value: + newPlanPackage(value); + break; + case NewPlanMatrixPrice value: + newPlanMatrix(value); + break; + case NewPlanThresholdTotalAmountPrice value: + newPlanThresholdTotalAmount(value); + break; + case NewPlanTieredPackagePrice value: + newPlanTieredPackage(value); + break; + case NewPlanTieredWithMinimumPrice value: + newPlanTieredWithMinimum(value); + break; + case NewPlanGroupedTieredPrice value: + newPlanGroupedTiered(value); + break; + case NewPlanTieredPackageWithMinimumPrice value: + newPlanTieredPackageWithMinimum(value); + break; + case NewPlanPackageWithAllocationPrice value: + newPlanPackageWithAllocation(value); + break; + case NewPlanUnitWithPercentPrice value: + newPlanUnitWithPercent(value); + break; + case NewPlanMatrixWithAllocationPrice value: + newPlanMatrixWithAllocation(value); + break; + case global::Orb.Models.Beta.TieredWithProration value: + tieredWithProration(value); + break; + case NewPlanUnitWithProrationPrice value: + newPlanUnitWithProration(value); + break; + case NewPlanGroupedAllocationPrice value: + newPlanGroupedAllocation(value); + break; + case NewPlanBulkWithProrationPrice value: + newPlanBulkWithProration(value); + break; + case NewPlanGroupedWithProratedMinimumPrice value: + newPlanGroupedWithProratedMinimum(value); + break; + case NewPlanGroupedWithMeteredMinimumPrice value: + newPlanGroupedWithMeteredMinimum(value); + break; + case global::Orb.Models.Beta.GroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewPlanMatrixWithDisplayNamePrice value: + newPlanMatrixWithDisplayName(value); + break; + case NewPlanGroupedTieredPackagePrice value: + newPlanGroupedTieredPackage(value); + break; + case NewPlanMaxGroupTieredPackagePrice value: + newPlanMaxGroupTieredPackage(value); + break; + case NewPlanScalableMatrixWithUnitPricingPrice value: + newPlanScalableMatrixWithUnitPricing(value); + break; + case NewPlanScalableMatrixWithTieredPricingPrice value: + newPlanScalableMatrixWithTieredPricing(value); + break; + case NewPlanCumulativeGroupedBulkPrice value: + newPlanCumulativeGroupedBulk(value); + break; + case global::Orb.Models.Beta.CumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewPlanMinimumCompositePrice value: + newPlanMinimumComposite(value); + break; + case global::Orb.Models.Beta.Percent value: + percent(value); + break; + case global::Orb.Models.Beta.EventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.BulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Beta.TieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Beta.GroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.CumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Beta.Percent value) => {...}, + /// (global::Orb.Models.Beta.EventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPlanUnit, + System::Func newPlanTiered, + System::Func newPlanBulk, + System::Func bulkWithFilters, + System::Func newPlanPackage, + System::Func newPlanMatrix, + System::Func newPlanThresholdTotalAmount, + System::Func newPlanTieredPackage, + System::Func newPlanTieredWithMinimum, + System::Func newPlanGroupedTiered, + System::Func newPlanTieredPackageWithMinimum, + System::Func newPlanPackageWithAllocation, + System::Func newPlanUnitWithPercent, + System::Func newPlanMatrixWithAllocation, + System::Func tieredWithProration, + System::Func newPlanUnitWithProration, + System::Func newPlanGroupedAllocation, + System::Func newPlanBulkWithProration, + System::Func newPlanGroupedWithProratedMinimum, + System::Func newPlanGroupedWithMeteredMinimum, + System::Func< + global::Orb.Models.Beta.GroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func newPlanMatrixWithDisplayName, + System::Func newPlanGroupedTieredPackage, + System::Func newPlanMaxGroupTieredPackage, + System::Func< + NewPlanScalableMatrixWithUnitPricingPrice, + T + > newPlanScalableMatrixWithUnitPricing, + System::Func< + NewPlanScalableMatrixWithTieredPricingPrice, + T + > newPlanScalableMatrixWithTieredPricing, + System::Func newPlanCumulativeGroupedBulk, + System::Func< + global::Orb.Models.Beta.CumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newPlanMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewPlanUnitPrice value => newPlanUnit(value), + NewPlanTieredPrice value => newPlanTiered(value), + NewPlanBulkPrice value => newPlanBulk(value), + global::Orb.Models.Beta.BulkWithFilters value => bulkWithFilters(value), + NewPlanPackagePrice value => newPlanPackage(value), + NewPlanMatrixPrice value => newPlanMatrix(value), + NewPlanThresholdTotalAmountPrice value => newPlanThresholdTotalAmount(value), + NewPlanTieredPackagePrice value => newPlanTieredPackage(value), + NewPlanTieredWithMinimumPrice value => newPlanTieredWithMinimum(value), + NewPlanGroupedTieredPrice value => newPlanGroupedTiered(value), + NewPlanTieredPackageWithMinimumPrice value => newPlanTieredPackageWithMinimum(value), + NewPlanPackageWithAllocationPrice value => newPlanPackageWithAllocation(value), + NewPlanUnitWithPercentPrice value => newPlanUnitWithPercent(value), + NewPlanMatrixWithAllocationPrice value => newPlanMatrixWithAllocation(value), + global::Orb.Models.Beta.TieredWithProration value => tieredWithProration(value), + NewPlanUnitWithProrationPrice value => newPlanUnitWithProration(value), + NewPlanGroupedAllocationPrice value => newPlanGroupedAllocation(value), + NewPlanBulkWithProrationPrice value => newPlanBulkWithProration(value), + NewPlanGroupedWithProratedMinimumPrice value => newPlanGroupedWithProratedMinimum( + value + ), + NewPlanGroupedWithMeteredMinimumPrice value => newPlanGroupedWithMeteredMinimum(value), + global::Orb.Models.Beta.GroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewPlanMatrixWithDisplayNamePrice value => newPlanMatrixWithDisplayName(value), + NewPlanGroupedTieredPackagePrice value => newPlanGroupedTieredPackage(value), + NewPlanMaxGroupTieredPackagePrice value => newPlanMaxGroupTieredPackage(value), + NewPlanScalableMatrixWithUnitPricingPrice value => newPlanScalableMatrixWithUnitPricing( + value + ), + NewPlanScalableMatrixWithTieredPricingPrice value => + newPlanScalableMatrixWithTieredPricing(value), + NewPlanCumulativeGroupedBulkPrice value => newPlanCumulativeGroupedBulk(value), + global::Orb.Models.Beta.CumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewPlanMinimumCompositePrice value => newPlanMinimumComposite(value), + global::Orb.Models.Beta.Percent value => percent(value), + global::Orb.Models.Beta.EventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Price"), + }; + } + + public static implicit operator global::Orb.Models.Beta.Price(NewPlanUnitPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Price(NewPlanTieredPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Price(NewPlanBulkPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + global::Orb.Models.Beta.BulkWithFilters value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price(NewPlanPackagePrice value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Price(NewPlanMatrixPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanGroupedTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanUnitWithPercentPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + global::Orb.Models.Beta.TieredWithProration value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanUnitWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanGroupedAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanBulkWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + global::Orb.Models.Beta.GroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + global::Orb.Models.Beta.CumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + NewPlanMinimumCompositePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + global::Orb.Models.Beta.Percent value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.Price( + global::Orb.Models.Beta.EventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + this.Switch( + (newPlanUnit) => newPlanUnit.Validate(), + (newPlanTiered) => newPlanTiered.Validate(), + (newPlanBulk) => newPlanBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newPlanPackage) => newPlanPackage.Validate(), + (newPlanMatrix) => newPlanMatrix.Validate(), + (newPlanThresholdTotalAmount) => newPlanThresholdTotalAmount.Validate(), + (newPlanTieredPackage) => newPlanTieredPackage.Validate(), + (newPlanTieredWithMinimum) => newPlanTieredWithMinimum.Validate(), + (newPlanGroupedTiered) => newPlanGroupedTiered.Validate(), + (newPlanTieredPackageWithMinimum) => newPlanTieredPackageWithMinimum.Validate(), + (newPlanPackageWithAllocation) => newPlanPackageWithAllocation.Validate(), + (newPlanUnitWithPercent) => newPlanUnitWithPercent.Validate(), + (newPlanMatrixWithAllocation) => newPlanMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newPlanUnitWithProration) => newPlanUnitWithProration.Validate(), + (newPlanGroupedAllocation) => newPlanGroupedAllocation.Validate(), + (newPlanBulkWithProration) => newPlanBulkWithProration.Validate(), + (newPlanGroupedWithProratedMinimum) => newPlanGroupedWithProratedMinimum.Validate(), + (newPlanGroupedWithMeteredMinimum) => newPlanGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newPlanMatrixWithDisplayName) => newPlanMatrixWithDisplayName.Validate(), + (newPlanGroupedTieredPackage) => newPlanGroupedTieredPackage.Validate(), + (newPlanMaxGroupTieredPackage) => newPlanMaxGroupTieredPackage.Validate(), + (newPlanScalableMatrixWithUnitPricing) => + newPlanScalableMatrixWithUnitPricing.Validate(), + (newPlanScalableMatrixWithTieredPricing) => + newPlanScalableMatrixWithTieredPricing.Validate(), + (newPlanCumulativeGroupedBulk) => newPlanCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newPlanMinimumComposite) => newPlanMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Beta.Price? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceConverter : JsonConverter +{ + public override global::Orb.Models.Beta.Price? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.Price(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.Price? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.BulkWithFilters, + global::Orb.Models.Beta.BulkWithFiltersFromRaw + >) +)] +public sealed record class BulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required global::Orb.Models.Beta.BulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public BulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public BulkWithFilters(global::Orb.Models.Beta.BulkWithFilters bulkWithFilters) + : base(bulkWithFilters) { } + + public BulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.BulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.BulkWithFiltersConfig, + global::Orb.Models.Beta.BulkWithFiltersConfigFromRaw + >) +)] +public sealed record class BulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithFiltersConfig() { } + + public BulkWithFiltersConfig( + global::Orb.Models.Beta.BulkWithFiltersConfig bulkWithFiltersConfig + ) + : base(bulkWithFiltersConfig) { } + + public BulkWithFiltersConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.BulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.Filter, + global::Orb.Models.Beta.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public Filter() { } + + public Filter(global::Orb.Models.Beta.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.Filter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class Tier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public Tier() { } + + public Tier(global::Orb.Models.Beta.Tier tier) + : base(tier) { } + + public Tier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Tier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Tier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class TierFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.Tier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.CadenceConverter))] +public enum Cadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CadenceConverter : JsonConverter +{ + public override global::Orb.Models.Beta.Cadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.Cadence.Annual, + "semi_annual" => global::Orb.Models.Beta.Cadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.Cadence.Monthly, + "quarterly" => global::Orb.Models.Beta.Cadence.Quarterly, + "one_time" => global::Orb.Models.Beta.Cadence.OneTime, + "custom" => global::Orb.Models.Beta.Cadence.Custom, + _ => (global::Orb.Models.Beta.Cadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.Cadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.Cadence.Annual => "annual", + global::Orb.Models.Beta.Cadence.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.Cadence.Monthly => "monthly", + global::Orb.Models.Beta.Cadence.Quarterly => "quarterly", + global::Orb.Models.Beta.Cadence.OneTime => "one_time", + global::Orb.Models.Beta.Cadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Beta.ConversionRateConfigConverter))] +public record class ConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ConversionRateConfig(SharedUnitConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(SharedTieredConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Beta.ConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.TieredWithProration, + global::Orb.Models.Beta.TieredWithProrationFromRaw + >) +)] +public sealed record class TieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required global::Orb.Models.Beta.TieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.TieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public TieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public TieredWithProration(global::Orb.Models.Beta.TieredWithProration tieredWithProration) + : base(tieredWithProration) { } + + public TieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.TieredWithProration.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.TieredWithProrationCadenceConverter))] +public enum TieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class TieredWithProrationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.TieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.TieredWithProrationCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.TieredWithProrationCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.TieredWithProrationCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.TieredWithProrationCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.TieredWithProrationCadence.OneTime, + "custom" => global::Orb.Models.Beta.TieredWithProrationCadence.Custom, + _ => (global::Orb.Models.Beta.TieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.TieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.TieredWithProrationCadence.Annual => "annual", + global::Orb.Models.Beta.TieredWithProrationCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.TieredWithProrationCadence.Monthly => "monthly", + global::Orb.Models.Beta.TieredWithProrationCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.TieredWithProrationCadence.OneTime => "one_time", + global::Orb.Models.Beta.TieredWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.TieredWithProrationConfig, + global::Orb.Models.Beta.TieredWithProrationConfigFromRaw + >) +)] +public sealed record class TieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredWithProrationConfig() { } + + public TieredWithProrationConfig( + global::Orb.Models.Beta.TieredWithProrationConfig tieredWithProrationConfig + ) + : base(tieredWithProrationConfig) { } + + public TieredWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.TieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.TieredWithProrationConfigTier, + global::Orb.Models.Beta.TieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class TieredWithProrationConfigTier : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithProrationConfigTier() { } + + public TieredWithProrationConfigTier( + global::Orb.Models.Beta.TieredWithProrationConfigTier tieredWithProrationConfigTier + ) + : base(tieredWithProrationConfigTier) { } + + public TieredWithProrationConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.TieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Beta.TieredWithProrationConversionRateConfigConverter))] +public record class TieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.TieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.TieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.TieredWithProrationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.TieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.GroupedWithMinMaxThresholds, + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public GroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public GroupedWithMinMaxThresholds( + global::Orb.Models.Beta.GroupedWithMinMaxThresholds groupedWithMinMaxThresholds + ) + : base(groupedWithMinMaxThresholds) { } + + public GroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.GroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadenceConverter))] +public enum GroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class GroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Custom, + _ => (global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Annual => "annual", + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfig, + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsConfig : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public GroupedWithMinMaxThresholdsConfig() { } + + public GroupedWithMinMaxThresholdsConfig( + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfig groupedWithMinMaxThresholdsConfig + ) + : base(groupedWithMinMaxThresholdsConfig) { } + + public GroupedWithMinMaxThresholdsConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class GroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.GroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.CumulativeGroupedAllocation, + global::Orb.Models.Beta.CumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required global::Orb.Models.Beta.CumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public CumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public CumulativeGroupedAllocation( + global::Orb.Models.Beta.CumulativeGroupedAllocation cumulativeGroupedAllocation + ) + : base(cumulativeGroupedAllocation) { } + + public CumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.CumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.CumulativeGroupedAllocationCadenceConverter))] +public enum CumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.CumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.OneTime, + "custom" => global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Custom, + _ => (global::Orb.Models.Beta.CumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Annual => "annual", + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Monthly => "monthly", + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.OneTime => "one_time", + global::Orb.Models.Beta.CumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.CumulativeGroupedAllocationConfig, + global::Orb.Models.Beta.CumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationConfig : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public CumulativeGroupedAllocationConfig() { } + + public CumulativeGroupedAllocationConfig( + global::Orb.Models.Beta.CumulativeGroupedAllocationConfig cumulativeGroupedAllocationConfig + ) + : base(cumulativeGroupedAllocationConfig) { } + + public CumulativeGroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.CumulativeGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class CumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.CumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.Percent, + global::Orb.Models.Beta.PercentFromRaw + >) +)] +public sealed record class Percent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required global::Orb.Models.Beta.PercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.PercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public Percent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public Percent(global::Orb.Models.Beta.Percent percent) + : base(percent) { } + + public Percent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.Percent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.PercentCadenceConverter))] +public enum PercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PercentCadenceConverter : JsonConverter +{ + public override global::Orb.Models.Beta.PercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.PercentCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.PercentCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.PercentCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.PercentCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.PercentCadence.OneTime, + "custom" => global::Orb.Models.Beta.PercentCadence.Custom, + _ => (global::Orb.Models.Beta.PercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.PercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.PercentCadence.Annual => "annual", + global::Orb.Models.Beta.PercentCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.PercentCadence.Monthly => "monthly", + global::Orb.Models.Beta.PercentCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.PercentCadence.OneTime => "one_time", + global::Orb.Models.Beta.PercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.PercentConfig, + global::Orb.Models.Beta.PercentConfigFromRaw + >) +)] +public sealed record class PercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PercentConfig() { } + + public PercentConfig(global::Orb.Models.Beta.PercentConfig percentConfig) + : base(percentConfig) { } + + public PercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PercentConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.PercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Beta.PercentConversionRateConfigConverter))] +public record class PercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.PercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.PercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Beta.PercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PercentConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.PercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.PercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.PercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.EventOutput, + global::Orb.Models.Beta.EventOutputFromRaw + >) +)] +public sealed record class EventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required global::Orb.Models.Beta.EventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.EventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public EventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public EventOutput(global::Orb.Models.Beta.EventOutput eventOutput) + : base(eventOutput) { } + + public EventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.EventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.EventOutputCadenceConverter))] +public enum EventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class EventOutputCadenceConverter : JsonConverter +{ + public override global::Orb.Models.Beta.EventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.EventOutputCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.EventOutputCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.EventOutputCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.EventOutputCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.EventOutputCadence.OneTime, + "custom" => global::Orb.Models.Beta.EventOutputCadence.Custom, + _ => (global::Orb.Models.Beta.EventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.EventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.EventOutputCadence.Annual => "annual", + global::Orb.Models.Beta.EventOutputCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.EventOutputCadence.Monthly => "monthly", + global::Orb.Models.Beta.EventOutputCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.EventOutputCadence.OneTime => "one_time", + global::Orb.Models.Beta.EventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.EventOutputConfig, + global::Orb.Models.Beta.EventOutputConfigFromRaw + >) +)] +public sealed record class EventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public EventOutputConfig() { } + + public EventOutputConfig(global::Orb.Models.Beta.EventOutputConfig eventOutputConfig) + : base(eventOutputConfig) { } + + public EventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class EventOutputConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.EventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Beta.EventOutputConversionRateConfigConverter))] +public record class EventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Beta.EventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EventOutputConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.EventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.EventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.EventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class RemoveAdjustment : JsonModel +{ + /// + /// The id of the adjustment to remove from on the plan. + /// + public required string AdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment_id"); } + init { JsonModel.Set(this._rawData, "adjustment_id", value); } + } + + /// + /// The phase to remove this adjustment from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + _ = this.AdjustmentID; + _ = this.PlanPhaseOrder; + } + + public RemoveAdjustment() { } + + public RemoveAdjustment(RemoveAdjustment removeAdjustment) + : base(removeAdjustment) { } + + public RemoveAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + RemoveAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static RemoveAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public RemoveAdjustment(string adjustmentID) + : this() + { + this.AdjustmentID = adjustmentID; + } +} + +class RemoveAdjustmentFromRaw : IFromRawJson +{ + /// + public RemoveAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + RemoveAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class RemovePrice : JsonModel +{ + /// + /// The id of the price to remove from the plan. + /// + public required string PriceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + /// The phase to remove this price from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + _ = this.PriceID; + _ = this.PlanPhaseOrder; + } + + public RemovePrice() { } + + public RemovePrice(RemovePrice removePrice) + : base(removePrice) { } + + public RemovePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + RemovePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static RemovePrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public RemovePrice(string priceID) + : this() + { + this.PriceID = priceID; + } +} + +class RemovePriceFromRaw : IFromRawJson +{ + /// + public RemovePrice FromRawUnchecked(IReadOnlyDictionary rawData) => + RemovePrice.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ReplaceAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the plan. + /// + public required ReplaceAdjustmentAdjustment Adjustment + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" + ); + } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The id of the adjustment on the plan to replace in the plan. + /// + public required string ReplacesAdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } + } + + /// + /// The phase to replace this adjustment from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.ReplacesAdjustmentID; + _ = this.PlanPhaseOrder; + } + + public ReplaceAdjustment() { } + + public ReplaceAdjustment(ReplaceAdjustment replaceAdjustment) + : base(replaceAdjustment) { } + + public ReplaceAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplaceAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplaceAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplaceAdjustmentFromRaw : IFromRawJson +{ + /// + public ReplaceAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + ReplaceAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the plan. +/// +[JsonConverter(typeof(ReplaceAdjustmentAdjustmentConverter))] +public record class ReplaceAdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public ReplaceAdjustmentAdjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ), + }; + } + + public static implicit operator ReplaceAdjustmentAdjustment(NewPercentageDiscount value) => + new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewUsageDiscount value) => + new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewAmountDiscount value) => + new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewMinimum value) => new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewMaximum value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(ReplaceAdjustmentAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplaceAdjustmentAdjustmentConverter : JsonConverter +{ + public override ReplaceAdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplaceAdjustmentAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplaceAdjustmentAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ReplacePrice : JsonModel +{ + /// + /// The id of the price on the plan to replace in the plan. + /// + public required string ReplacesPriceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// The allocation price to add to the plan. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// The phase to replace this price from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New plan price request body params. + /// + public ReplacePricePrice? Price + { + get { return JsonModel.GetNullableClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + public override void Validate() + { + _ = this.ReplacesPriceID; + this.AllocationPrice?.Validate(); + _ = this.PlanPhaseOrder; + this.Price?.Validate(); + } + + public ReplacePrice() { } + + public ReplacePrice(ReplacePrice replacePrice) + : base(replacePrice) { } + + public ReplacePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePrice(string replacesPriceID) + : this() + { + this.ReplacesPriceID = replacesPriceID; + } +} + +class ReplacePriceFromRaw : IFromRawJson +{ + /// + public ReplacePrice FromRawUnchecked(IReadOnlyDictionary rawData) => + ReplacePrice.FromRawUnchecked(rawData); +} + +/// +/// New plan price request body params. +/// +[JsonConverter(typeof(ReplacePricePriceConverter))] +public record class ReplacePricePrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newPlanUnit: (x) => x.ItemID, + newPlanTiered: (x) => x.ItemID, + newPlanBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newPlanPackage: (x) => x.ItemID, + newPlanMatrix: (x) => x.ItemID, + newPlanThresholdTotalAmount: (x) => x.ItemID, + newPlanTieredPackage: (x) => x.ItemID, + newPlanTieredWithMinimum: (x) => x.ItemID, + newPlanGroupedTiered: (x) => x.ItemID, + newPlanTieredPackageWithMinimum: (x) => x.ItemID, + newPlanPackageWithAllocation: (x) => x.ItemID, + newPlanUnitWithPercent: (x) => x.ItemID, + newPlanMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newPlanUnitWithProration: (x) => x.ItemID, + newPlanGroupedAllocation: (x) => x.ItemID, + newPlanBulkWithProration: (x) => x.ItemID, + newPlanGroupedWithProratedMinimum: (x) => x.ItemID, + newPlanGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newPlanMatrixWithDisplayName: (x) => x.ItemID, + newPlanGroupedTieredPackage: (x) => x.ItemID, + newPlanMaxGroupTieredPackage: (x) => x.ItemID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ItemID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ItemID, + newPlanCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newPlanMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newPlanUnit: (x) => x.Name, + newPlanTiered: (x) => x.Name, + newPlanBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newPlanPackage: (x) => x.Name, + newPlanMatrix: (x) => x.Name, + newPlanThresholdTotalAmount: (x) => x.Name, + newPlanTieredPackage: (x) => x.Name, + newPlanTieredWithMinimum: (x) => x.Name, + newPlanGroupedTiered: (x) => x.Name, + newPlanTieredPackageWithMinimum: (x) => x.Name, + newPlanPackageWithAllocation: (x) => x.Name, + newPlanUnitWithPercent: (x) => x.Name, + newPlanMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newPlanUnitWithProration: (x) => x.Name, + newPlanGroupedAllocation: (x) => x.Name, + newPlanBulkWithProration: (x) => x.Name, + newPlanGroupedWithProratedMinimum: (x) => x.Name, + newPlanGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newPlanMatrixWithDisplayName: (x) => x.Name, + newPlanGroupedTieredPackage: (x) => x.Name, + newPlanMaxGroupTieredPackage: (x) => x.Name, + newPlanScalableMatrixWithUnitPricing: (x) => x.Name, + newPlanScalableMatrixWithTieredPricing: (x) => x.Name, + newPlanCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newPlanMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newPlanUnit: (x) => x.BillableMetricID, + newPlanTiered: (x) => x.BillableMetricID, + newPlanBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newPlanPackage: (x) => x.BillableMetricID, + newPlanMatrix: (x) => x.BillableMetricID, + newPlanThresholdTotalAmount: (x) => x.BillableMetricID, + newPlanTieredPackage: (x) => x.BillableMetricID, + newPlanTieredWithMinimum: (x) => x.BillableMetricID, + newPlanGroupedTiered: (x) => x.BillableMetricID, + newPlanTieredPackageWithMinimum: (x) => x.BillableMetricID, + newPlanPackageWithAllocation: (x) => x.BillableMetricID, + newPlanUnitWithPercent: (x) => x.BillableMetricID, + newPlanMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newPlanUnitWithProration: (x) => x.BillableMetricID, + newPlanGroupedAllocation: (x) => x.BillableMetricID, + newPlanBulkWithProration: (x) => x.BillableMetricID, + newPlanGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newPlanGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newPlanMatrixWithDisplayName: (x) => x.BillableMetricID, + newPlanGroupedTieredPackage: (x) => x.BillableMetricID, + newPlanMaxGroupTieredPackage: (x) => x.BillableMetricID, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newPlanCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newPlanMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newPlanUnit: (x) => x.BilledInAdvance, + newPlanTiered: (x) => x.BilledInAdvance, + newPlanBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newPlanPackage: (x) => x.BilledInAdvance, + newPlanMatrix: (x) => x.BilledInAdvance, + newPlanThresholdTotalAmount: (x) => x.BilledInAdvance, + newPlanTieredPackage: (x) => x.BilledInAdvance, + newPlanTieredWithMinimum: (x) => x.BilledInAdvance, + newPlanGroupedTiered: (x) => x.BilledInAdvance, + newPlanTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newPlanPackageWithAllocation: (x) => x.BilledInAdvance, + newPlanUnitWithPercent: (x) => x.BilledInAdvance, + newPlanMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newPlanUnitWithProration: (x) => x.BilledInAdvance, + newPlanGroupedAllocation: (x) => x.BilledInAdvance, + newPlanBulkWithProration: (x) => x.BilledInAdvance, + newPlanGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newPlanGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newPlanMatrixWithDisplayName: (x) => x.BilledInAdvance, + newPlanGroupedTieredPackage: (x) => x.BilledInAdvance, + newPlanMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newPlanCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newPlanMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.BillingCycleConfiguration, + newPlanTiered: (x) => x.BillingCycleConfiguration, + newPlanBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newPlanPackage: (x) => x.BillingCycleConfiguration, + newPlanMatrix: (x) => x.BillingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newPlanTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedTiered: (x) => x.BillingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newPlanUnitWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanBulkWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newPlanUnit: (x) => x.ConversionRate, + newPlanTiered: (x) => x.ConversionRate, + newPlanBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newPlanPackage: (x) => x.ConversionRate, + newPlanMatrix: (x) => x.ConversionRate, + newPlanThresholdTotalAmount: (x) => x.ConversionRate, + newPlanTieredPackage: (x) => x.ConversionRate, + newPlanTieredWithMinimum: (x) => x.ConversionRate, + newPlanGroupedTiered: (x) => x.ConversionRate, + newPlanTieredPackageWithMinimum: (x) => x.ConversionRate, + newPlanPackageWithAllocation: (x) => x.ConversionRate, + newPlanUnitWithPercent: (x) => x.ConversionRate, + newPlanMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newPlanUnitWithProration: (x) => x.ConversionRate, + newPlanGroupedAllocation: (x) => x.ConversionRate, + newPlanBulkWithProration: (x) => x.ConversionRate, + newPlanGroupedWithProratedMinimum: (x) => x.ConversionRate, + newPlanGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newPlanMatrixWithDisplayName: (x) => x.ConversionRate, + newPlanGroupedTieredPackage: (x) => x.ConversionRate, + newPlanMaxGroupTieredPackage: (x) => x.ConversionRate, + newPlanScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newPlanScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newPlanCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newPlanMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newPlanUnit: (x) => x.Currency, + newPlanTiered: (x) => x.Currency, + newPlanBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newPlanPackage: (x) => x.Currency, + newPlanMatrix: (x) => x.Currency, + newPlanThresholdTotalAmount: (x) => x.Currency, + newPlanTieredPackage: (x) => x.Currency, + newPlanTieredWithMinimum: (x) => x.Currency, + newPlanGroupedTiered: (x) => x.Currency, + newPlanTieredPackageWithMinimum: (x) => x.Currency, + newPlanPackageWithAllocation: (x) => x.Currency, + newPlanUnitWithPercent: (x) => x.Currency, + newPlanMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newPlanUnitWithProration: (x) => x.Currency, + newPlanGroupedAllocation: (x) => x.Currency, + newPlanBulkWithProration: (x) => x.Currency, + newPlanGroupedWithProratedMinimum: (x) => x.Currency, + newPlanGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newPlanMatrixWithDisplayName: (x) => x.Currency, + newPlanGroupedTieredPackage: (x) => x.Currency, + newPlanMaxGroupTieredPackage: (x) => x.Currency, + newPlanScalableMatrixWithUnitPricing: (x) => x.Currency, + newPlanScalableMatrixWithTieredPricing: (x) => x.Currency, + newPlanCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newPlanMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.DimensionalPriceConfiguration, + newPlanTiered: (x) => x.DimensionalPriceConfiguration, + newPlanBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newPlanPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMatrix: (x) => x.DimensionalPriceConfiguration, + newPlanThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newPlanUnit: (x) => x.ExternalPriceID, + newPlanTiered: (x) => x.ExternalPriceID, + newPlanBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newPlanPackage: (x) => x.ExternalPriceID, + newPlanMatrix: (x) => x.ExternalPriceID, + newPlanThresholdTotalAmount: (x) => x.ExternalPriceID, + newPlanTieredPackage: (x) => x.ExternalPriceID, + newPlanTieredWithMinimum: (x) => x.ExternalPriceID, + newPlanGroupedTiered: (x) => x.ExternalPriceID, + newPlanTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newPlanPackageWithAllocation: (x) => x.ExternalPriceID, + newPlanUnitWithPercent: (x) => x.ExternalPriceID, + newPlanMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newPlanUnitWithProration: (x) => x.ExternalPriceID, + newPlanGroupedAllocation: (x) => x.ExternalPriceID, + newPlanBulkWithProration: (x) => x.ExternalPriceID, + newPlanGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newPlanMatrixWithDisplayName: (x) => x.ExternalPriceID, + newPlanGroupedTieredPackage: (x) => x.ExternalPriceID, + newPlanMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newPlanCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newPlanMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newPlanUnit: (x) => x.FixedPriceQuantity, + newPlanTiered: (x) => x.FixedPriceQuantity, + newPlanBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newPlanPackage: (x) => x.FixedPriceQuantity, + newPlanMatrix: (x) => x.FixedPriceQuantity, + newPlanThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newPlanTieredPackage: (x) => x.FixedPriceQuantity, + newPlanTieredWithMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedTiered: (x) => x.FixedPriceQuantity, + newPlanTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newPlanPackageWithAllocation: (x) => x.FixedPriceQuantity, + newPlanUnitWithPercent: (x) => x.FixedPriceQuantity, + newPlanMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newPlanUnitWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanBulkWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newPlanMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newPlanGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newPlanMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newPlanCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newPlanUnit: (x) => x.InvoiceGroupingKey, + newPlanTiered: (x) => x.InvoiceGroupingKey, + newPlanBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newPlanPackage: (x) => x.InvoiceGroupingKey, + newPlanMatrix: (x) => x.InvoiceGroupingKey, + newPlanThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newPlanTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedTiered: (x) => x.InvoiceGroupingKey, + newPlanTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newPlanUnitWithPercent: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newPlanUnitWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanBulkWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newPlanGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newPlanCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.InvoicingCycleConfiguration, + newPlanTiered: (x) => x.InvoicingCycleConfiguration, + newPlanBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newPlanPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMatrix: (x) => x.InvoicingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newPlanUnit: (x) => x.ReferenceID, + newPlanTiered: (x) => x.ReferenceID, + newPlanBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newPlanPackage: (x) => x.ReferenceID, + newPlanMatrix: (x) => x.ReferenceID, + newPlanThresholdTotalAmount: (x) => x.ReferenceID, + newPlanTieredPackage: (x) => x.ReferenceID, + newPlanTieredWithMinimum: (x) => x.ReferenceID, + newPlanGroupedTiered: (x) => x.ReferenceID, + newPlanTieredPackageWithMinimum: (x) => x.ReferenceID, + newPlanPackageWithAllocation: (x) => x.ReferenceID, + newPlanUnitWithPercent: (x) => x.ReferenceID, + newPlanMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newPlanUnitWithProration: (x) => x.ReferenceID, + newPlanGroupedAllocation: (x) => x.ReferenceID, + newPlanBulkWithProration: (x) => x.ReferenceID, + newPlanGroupedWithProratedMinimum: (x) => x.ReferenceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newPlanMatrixWithDisplayName: (x) => x.ReferenceID, + newPlanGroupedTieredPackage: (x) => x.ReferenceID, + newPlanMaxGroupTieredPackage: (x) => x.ReferenceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newPlanCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newPlanMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public ReplacePricePrice(NewPlanUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(ReplacePricePriceBulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanTieredPackageWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + ReplacePricePriceTieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanGroupedWithProratedMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanGroupedWithMeteredMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + ReplacePricePriceGroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + ReplacePricePriceCumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(ReplacePricePricePercent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(ReplacePricePriceEventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnit(out var value)) { + /// // `value` is of type `NewPlanUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnit([NotNullWhen(true)] out NewPlanUnitPrice? value) + { + value = this.Value as NewPlanUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTiered(out var value)) { + /// // `value` is of type `NewPlanTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTiered([NotNullWhen(true)] out NewPlanTieredPrice? value) + { + value = this.Value as NewPlanTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulk(out var value)) { + /// // `value` is of type `NewPlanBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulk([NotNullWhen(true)] out NewPlanBulkPrice? value) + { + value = this.Value as NewPlanBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `ReplacePricePriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out ReplacePricePriceBulkWithFilters? value + ) + { + value = this.Value as ReplacePricePriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackage(out var value)) { + /// // `value` is of type `NewPlanPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackage([NotNullWhen(true)] out NewPlanPackagePrice? value) + { + value = this.Value as NewPlanPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrix(out var value)) { + /// // `value` is of type `NewPlanMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrix([NotNullWhen(true)] out NewPlanMatrixPrice? value) + { + value = this.Value as NewPlanMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewPlanThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanThresholdTotalAmount( + [NotNullWhen(true)] out NewPlanThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewPlanThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackage(out var value)) { + /// // `value` is of type `NewPlanTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackage( + [NotNullWhen(true)] out NewPlanTieredPackagePrice? value + ) + { + value = this.Value as NewPlanTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredWithMinimum( + [NotNullWhen(true)] out NewPlanTieredWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTiered(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTiered( + [NotNullWhen(true)] out NewPlanGroupedTieredPrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackageWithMinimum( + [NotNullWhen(true)] out NewPlanTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackageWithAllocation(out var value)) { + /// // `value` is of type `NewPlanPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackageWithAllocation( + [NotNullWhen(true)] out NewPlanPackageWithAllocationPrice? value + ) + { + value = this.Value as NewPlanPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithPercent(out var value)) { + /// // `value` is of type `NewPlanUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithPercent( + [NotNullWhen(true)] out NewPlanUnitWithPercentPrice? value + ) + { + value = this.Value as NewPlanUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewPlanMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithAllocation( + [NotNullWhen(true)] out NewPlanMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewPlanMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `ReplacePricePriceTieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] out ReplacePricePriceTieredWithProration? value + ) + { + value = this.Value as ReplacePricePriceTieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithProration(out var value)) { + /// // `value` is of type `NewPlanUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithProration( + [NotNullWhen(true)] out NewPlanUnitWithProrationPrice? value + ) + { + value = this.Value as NewPlanUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedAllocation(out var value)) { + /// // `value` is of type `NewPlanGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedAllocation( + [NotNullWhen(true)] out NewPlanGroupedAllocationPrice? value + ) + { + value = this.Value as NewPlanGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulkWithProration(out var value)) { + /// // `value` is of type `NewPlanBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulkWithProration( + [NotNullWhen(true)] out NewPlanBulkWithProrationPrice? value + ) + { + value = this.Value as NewPlanBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `ReplacePricePriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out ReplacePricePriceGroupedWithMinMaxThresholds? value + ) + { + value = this.Value as ReplacePricePriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewPlanMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithDisplayName( + [NotNullWhen(true)] out NewPlanMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewPlanMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTieredPackage( + [NotNullWhen(true)] out NewPlanGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewPlanMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMaxGroupTieredPackage( + [NotNullWhen(true)] out NewPlanMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewPlanMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewPlanCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanCumulativeGroupedBulk( + [NotNullWhen(true)] out NewPlanCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewPlanCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `ReplacePricePriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out ReplacePricePriceCumulativeGroupedAllocation? value + ) + { + value = this.Value as ReplacePricePriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMinimumComposite(out var value)) { + /// // `value` is of type `NewPlanMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMinimumComposite( + [NotNullWhen(true)] out NewPlanMinimumCompositePrice? value + ) + { + value = this.Value as NewPlanMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `ReplacePricePricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out ReplacePricePricePercent? value) + { + value = this.Value as ReplacePricePricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `ReplacePricePriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput([NotNullWhen(true)] out ReplacePricePriceEventOutput? value) + { + value = this.Value as ReplacePricePriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (ReplacePricePriceBulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (ReplacePricePriceTieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (ReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (ReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (ReplacePricePricePercent value) => {...}, + /// (ReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPlanUnit, + System::Action newPlanTiered, + System::Action newPlanBulk, + System::Action bulkWithFilters, + System::Action newPlanPackage, + System::Action newPlanMatrix, + System::Action newPlanThresholdTotalAmount, + System::Action newPlanTieredPackage, + System::Action newPlanTieredWithMinimum, + System::Action newPlanGroupedTiered, + System::Action newPlanTieredPackageWithMinimum, + System::Action newPlanPackageWithAllocation, + System::Action newPlanUnitWithPercent, + System::Action newPlanMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newPlanUnitWithProration, + System::Action newPlanGroupedAllocation, + System::Action newPlanBulkWithProration, + System::Action newPlanGroupedWithProratedMinimum, + System::Action newPlanGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newPlanMatrixWithDisplayName, + System::Action newPlanGroupedTieredPackage, + System::Action newPlanMaxGroupTieredPackage, + System::Action newPlanScalableMatrixWithUnitPricing, + System::Action newPlanScalableMatrixWithTieredPricing, + System::Action newPlanCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newPlanMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewPlanUnitPrice value: + newPlanUnit(value); + break; + case NewPlanTieredPrice value: + newPlanTiered(value); + break; + case NewPlanBulkPrice value: + newPlanBulk(value); + break; + case ReplacePricePriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewPlanPackagePrice value: + newPlanPackage(value); + break; + case NewPlanMatrixPrice value: + newPlanMatrix(value); + break; + case NewPlanThresholdTotalAmountPrice value: + newPlanThresholdTotalAmount(value); + break; + case NewPlanTieredPackagePrice value: + newPlanTieredPackage(value); + break; + case NewPlanTieredWithMinimumPrice value: + newPlanTieredWithMinimum(value); + break; + case NewPlanGroupedTieredPrice value: + newPlanGroupedTiered(value); + break; + case NewPlanTieredPackageWithMinimumPrice value: + newPlanTieredPackageWithMinimum(value); + break; + case NewPlanPackageWithAllocationPrice value: + newPlanPackageWithAllocation(value); + break; + case NewPlanUnitWithPercentPrice value: + newPlanUnitWithPercent(value); + break; + case NewPlanMatrixWithAllocationPrice value: + newPlanMatrixWithAllocation(value); + break; + case ReplacePricePriceTieredWithProration value: + tieredWithProration(value); + break; + case NewPlanUnitWithProrationPrice value: + newPlanUnitWithProration(value); + break; + case NewPlanGroupedAllocationPrice value: + newPlanGroupedAllocation(value); + break; + case NewPlanBulkWithProrationPrice value: + newPlanBulkWithProration(value); + break; + case NewPlanGroupedWithProratedMinimumPrice value: + newPlanGroupedWithProratedMinimum(value); + break; + case NewPlanGroupedWithMeteredMinimumPrice value: + newPlanGroupedWithMeteredMinimum(value); + break; + case ReplacePricePriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewPlanMatrixWithDisplayNamePrice value: + newPlanMatrixWithDisplayName(value); + break; + case NewPlanGroupedTieredPackagePrice value: + newPlanGroupedTieredPackage(value); + break; + case NewPlanMaxGroupTieredPackagePrice value: + newPlanMaxGroupTieredPackage(value); + break; + case NewPlanScalableMatrixWithUnitPricingPrice value: + newPlanScalableMatrixWithUnitPricing(value); + break; + case NewPlanScalableMatrixWithTieredPricingPrice value: + newPlanScalableMatrixWithTieredPricing(value); + break; + case NewPlanCumulativeGroupedBulkPrice value: + newPlanCumulativeGroupedBulk(value); + break; + case ReplacePricePriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewPlanMinimumCompositePrice value: + newPlanMinimumComposite(value); + break; + case ReplacePricePricePercent value: + percent(value); + break; + case ReplacePricePriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (ReplacePricePriceBulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (ReplacePricePriceTieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (ReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (ReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (ReplacePricePricePercent value) => {...}, + /// (ReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPlanUnit, + System::Func newPlanTiered, + System::Func newPlanBulk, + System::Func bulkWithFilters, + System::Func newPlanPackage, + System::Func newPlanMatrix, + System::Func newPlanThresholdTotalAmount, + System::Func newPlanTieredPackage, + System::Func newPlanTieredWithMinimum, + System::Func newPlanGroupedTiered, + System::Func newPlanTieredPackageWithMinimum, + System::Func newPlanPackageWithAllocation, + System::Func newPlanUnitWithPercent, + System::Func newPlanMatrixWithAllocation, + System::Func tieredWithProration, + System::Func newPlanUnitWithProration, + System::Func newPlanGroupedAllocation, + System::Func newPlanBulkWithProration, + System::Func newPlanGroupedWithProratedMinimum, + System::Func newPlanGroupedWithMeteredMinimum, + System::Func groupedWithMinMaxThresholds, + System::Func newPlanMatrixWithDisplayName, + System::Func newPlanGroupedTieredPackage, + System::Func newPlanMaxGroupTieredPackage, + System::Func< + NewPlanScalableMatrixWithUnitPricingPrice, + T + > newPlanScalableMatrixWithUnitPricing, + System::Func< + NewPlanScalableMatrixWithTieredPricingPrice, + T + > newPlanScalableMatrixWithTieredPricing, + System::Func newPlanCumulativeGroupedBulk, + System::Func cumulativeGroupedAllocation, + System::Func newPlanMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewPlanUnitPrice value => newPlanUnit(value), + NewPlanTieredPrice value => newPlanTiered(value), + NewPlanBulkPrice value => newPlanBulk(value), + ReplacePricePriceBulkWithFilters value => bulkWithFilters(value), + NewPlanPackagePrice value => newPlanPackage(value), + NewPlanMatrixPrice value => newPlanMatrix(value), + NewPlanThresholdTotalAmountPrice value => newPlanThresholdTotalAmount(value), + NewPlanTieredPackagePrice value => newPlanTieredPackage(value), + NewPlanTieredWithMinimumPrice value => newPlanTieredWithMinimum(value), + NewPlanGroupedTieredPrice value => newPlanGroupedTiered(value), + NewPlanTieredPackageWithMinimumPrice value => newPlanTieredPackageWithMinimum(value), + NewPlanPackageWithAllocationPrice value => newPlanPackageWithAllocation(value), + NewPlanUnitWithPercentPrice value => newPlanUnitWithPercent(value), + NewPlanMatrixWithAllocationPrice value => newPlanMatrixWithAllocation(value), + ReplacePricePriceTieredWithProration value => tieredWithProration(value), + NewPlanUnitWithProrationPrice value => newPlanUnitWithProration(value), + NewPlanGroupedAllocationPrice value => newPlanGroupedAllocation(value), + NewPlanBulkWithProrationPrice value => newPlanBulkWithProration(value), + NewPlanGroupedWithProratedMinimumPrice value => newPlanGroupedWithProratedMinimum( + value + ), + NewPlanGroupedWithMeteredMinimumPrice value => newPlanGroupedWithMeteredMinimum(value), + ReplacePricePriceGroupedWithMinMaxThresholds value => groupedWithMinMaxThresholds( + value + ), + NewPlanMatrixWithDisplayNamePrice value => newPlanMatrixWithDisplayName(value), + NewPlanGroupedTieredPackagePrice value => newPlanGroupedTieredPackage(value), + NewPlanMaxGroupTieredPackagePrice value => newPlanMaxGroupTieredPackage(value), + NewPlanScalableMatrixWithUnitPricingPrice value => newPlanScalableMatrixWithUnitPricing( + value + ), + NewPlanScalableMatrixWithTieredPricingPrice value => + newPlanScalableMatrixWithTieredPricing(value), + NewPlanCumulativeGroupedBulkPrice value => newPlanCumulativeGroupedBulk(value), + ReplacePricePriceCumulativeGroupedAllocation value => cumulativeGroupedAllocation( + value + ), + NewPlanMinimumCompositePrice value => newPlanMinimumComposite(value), + ReplacePricePricePercent value => percent(value), + ReplacePricePriceEventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ), + }; + } + + public static implicit operator ReplacePricePrice(NewPlanUnitPrice value) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanTieredPrice value) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanBulkPrice value) => new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePriceBulkWithFilters value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanPackagePrice value) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanMatrixPrice value) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanThresholdTotalAmountPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanTieredPackagePrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanTieredWithMinimumPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanGroupedTieredPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanTieredPackageWithMinimumPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanPackageWithAllocationPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanUnitWithPercentPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanMatrixWithAllocationPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePriceTieredWithProration value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanUnitWithProrationPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanGroupedAllocationPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanBulkWithProrationPrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewPlanGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewPlanGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + ReplacePricePriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanMatrixWithDisplayNamePrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanGroupedTieredPackagePrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewPlanMaxGroupTieredPackagePrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewPlanScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewPlanScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanCumulativeGroupedBulkPrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + ReplacePricePriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewPlanMinimumCompositePrice value) => + new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePricePercent value) => new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePriceEventOutput value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ); + } + this.Switch( + (newPlanUnit) => newPlanUnit.Validate(), + (newPlanTiered) => newPlanTiered.Validate(), + (newPlanBulk) => newPlanBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newPlanPackage) => newPlanPackage.Validate(), + (newPlanMatrix) => newPlanMatrix.Validate(), + (newPlanThresholdTotalAmount) => newPlanThresholdTotalAmount.Validate(), + (newPlanTieredPackage) => newPlanTieredPackage.Validate(), + (newPlanTieredWithMinimum) => newPlanTieredWithMinimum.Validate(), + (newPlanGroupedTiered) => newPlanGroupedTiered.Validate(), + (newPlanTieredPackageWithMinimum) => newPlanTieredPackageWithMinimum.Validate(), + (newPlanPackageWithAllocation) => newPlanPackageWithAllocation.Validate(), + (newPlanUnitWithPercent) => newPlanUnitWithPercent.Validate(), + (newPlanMatrixWithAllocation) => newPlanMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newPlanUnitWithProration) => newPlanUnitWithProration.Validate(), + (newPlanGroupedAllocation) => newPlanGroupedAllocation.Validate(), + (newPlanBulkWithProration) => newPlanBulkWithProration.Validate(), + (newPlanGroupedWithProratedMinimum) => newPlanGroupedWithProratedMinimum.Validate(), + (newPlanGroupedWithMeteredMinimum) => newPlanGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newPlanMatrixWithDisplayName) => newPlanMatrixWithDisplayName.Validate(), + (newPlanGroupedTieredPackage) => newPlanGroupedTieredPackage.Validate(), + (newPlanMaxGroupTieredPackage) => newPlanMaxGroupTieredPackage.Validate(), + (newPlanScalableMatrixWithUnitPricing) => + newPlanScalableMatrixWithUnitPricing.Validate(), + (newPlanScalableMatrixWithTieredPricing) => + newPlanScalableMatrixWithTieredPricing.Validate(), + (newPlanCumulativeGroupedBulk) => newPlanCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newPlanMinimumComposite) => newPlanMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(ReplacePricePrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceConverter : JsonConverter +{ + public override ReplacePricePrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFilters, + ReplacePricePriceBulkWithFiltersFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public ReplacePricePriceBulkWithFilters( + ReplacePricePriceBulkWithFilters replacePricePriceBulkWithFilters + ) + : base(replacePricePriceBulkWithFilters) { } + + public ReplacePricePriceBulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersFromRaw : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig, + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig replacePricePriceBulkWithFiltersBulkWithFiltersConfig + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfig) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter, + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter replacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier, + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier replacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfigTier) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceBulkWithFiltersCadenceConverter))] +public enum ReplacePricePriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceBulkWithFiltersCadence.Annual, + "semi_annual" => ReplacePricePriceBulkWithFiltersCadence.SemiAnnual, + "monthly" => ReplacePricePriceBulkWithFiltersCadence.Monthly, + "quarterly" => ReplacePricePriceBulkWithFiltersCadence.Quarterly, + "one_time" => ReplacePricePriceBulkWithFiltersCadence.OneTime, + "custom" => ReplacePricePriceBulkWithFiltersCadence.Custom, + _ => (ReplacePricePriceBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceBulkWithFiltersCadence.Annual => "annual", + ReplacePricePriceBulkWithFiltersCadence.SemiAnnual => "semi_annual", + ReplacePricePriceBulkWithFiltersCadence.Monthly => "monthly", + ReplacePricePriceBulkWithFiltersCadence.Quarterly => "quarterly", + ReplacePricePriceBulkWithFiltersCadence.OneTime => "one_time", + ReplacePricePriceBulkWithFiltersCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ReplacePricePriceBulkWithFiltersConversionRateConfigConverter))] +public record class ReplacePricePriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePriceBulkWithFiltersConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceBulkWithFiltersConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceTieredWithProration, + ReplacePricePriceTieredWithProrationFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required ReplacePricePriceTieredWithProrationTieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceTieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceTieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public ReplacePricePriceTieredWithProration( + ReplacePricePriceTieredWithProration replacePricePriceTieredWithProration + ) + : base(replacePricePriceTieredWithProration) { } + + public ReplacePricePriceTieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceTieredWithProrationFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceTieredWithProration.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceTieredWithProrationCadenceConverter))] +public enum ReplacePricePriceTieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceTieredWithProrationCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceTieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceTieredWithProrationCadence.Annual, + "semi_annual" => ReplacePricePriceTieredWithProrationCadence.SemiAnnual, + "monthly" => ReplacePricePriceTieredWithProrationCadence.Monthly, + "quarterly" => ReplacePricePriceTieredWithProrationCadence.Quarterly, + "one_time" => ReplacePricePriceTieredWithProrationCadence.OneTime, + "custom" => ReplacePricePriceTieredWithProrationCadence.Custom, + _ => (ReplacePricePriceTieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceTieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceTieredWithProrationCadence.Annual => "annual", + ReplacePricePriceTieredWithProrationCadence.SemiAnnual => "semi_annual", + ReplacePricePriceTieredWithProrationCadence.Monthly => "monthly", + ReplacePricePriceTieredWithProrationCadence.Quarterly => "quarterly", + ReplacePricePriceTieredWithProrationCadence.OneTime => "one_time", + ReplacePricePriceTieredWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceTieredWithProrationTieredWithProrationConfig, + ReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProrationTieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig() { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + ReplacePricePriceTieredWithProrationTieredWithProrationConfig replacePricePriceTieredWithProrationTieredWithProrationConfig + ) + : base(replacePricePriceTieredWithProrationTieredWithProrationConfig) { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class ReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceTieredWithProrationTieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier, + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier() { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier replacePricePriceTieredWithProrationTieredWithProrationConfigTier + ) + : base(replacePricePriceTieredWithProrationTieredWithProrationConfigTier) { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReplacePricePriceTieredWithProrationConversionRateConfigConverter))] +public record class ReplacePricePriceTieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePriceTieredWithProrationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceTieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceTieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceTieredWithProrationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceTieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceGroupedWithMinMaxThresholds, + ReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class ReplacePricePriceGroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public ReplacePricePriceGroupedWithMinMaxThresholds( + ReplacePricePriceGroupedWithMinMaxThresholds replacePricePriceGroupedWithMinMaxThresholds + ) + : base(replacePricePriceGroupedWithMinMaxThresholds) { } + + public ReplacePricePriceGroupedWithMinMaxThresholds( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceGroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceGroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter))] +public enum ReplacePricePriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom, + _ => (ReplacePricePriceGroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual => "annual", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual => "semi_annual", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly => "quarterly", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() { } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig replacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base(replacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig) { } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter))] +public record class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceCumulativeGroupedAllocation, + ReplacePricePriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class ReplacePricePriceCumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public ReplacePricePriceCumulativeGroupedAllocation( + ReplacePricePriceCumulativeGroupedAllocation replacePricePriceCumulativeGroupedAllocation + ) + : base(replacePricePriceCumulativeGroupedAllocation) { } + + public ReplacePricePriceCumulativeGroupedAllocation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceCumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceCumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceCumulativeGroupedAllocationCadenceConverter))] +public enum ReplacePricePriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime, + "custom" => ReplacePricePriceCumulativeGroupedAllocationCadence.Custom, + _ => (ReplacePricePriceCumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceCumulativeGroupedAllocationCadence.Annual => "annual", + ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual => "semi_annual", + ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly => "monthly", + ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly => "quarterly", + ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime => "one_time", + ReplacePricePriceCumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() { } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig replacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base(replacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig) { } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter))] +public record class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ReplacePricePricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required ReplacePricePricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public ReplacePricePricePercent(ReplacePricePricePercent replacePricePricePercent) + : base(replacePricePricePercent) { } + + public ReplacePricePricePercent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePricePercent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePricePercentFromRaw : IFromRawJson +{ + /// + public ReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePricePercentCadenceConverter))] +public enum ReplacePricePricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePricePercentCadenceConverter + : JsonConverter +{ + public override ReplacePricePricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePricePercentCadence.Annual, + "semi_annual" => ReplacePricePricePercentCadence.SemiAnnual, + "monthly" => ReplacePricePricePercentCadence.Monthly, + "quarterly" => ReplacePricePricePercentCadence.Quarterly, + "one_time" => ReplacePricePricePercentCadence.OneTime, + "custom" => ReplacePricePricePercentCadence.Custom, + _ => (ReplacePricePricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePricePercentCadence.Annual => "annual", + ReplacePricePricePercentCadence.SemiAnnual => "semi_annual", + ReplacePricePricePercentCadence.Monthly => "monthly", + ReplacePricePricePercentCadence.Quarterly => "quarterly", + ReplacePricePricePercentCadence.OneTime => "one_time", + ReplacePricePricePercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePricePercentPercentConfig, + ReplacePricePricePercentPercentConfigFromRaw + >) +)] +public sealed record class ReplacePricePricePercentPercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public ReplacePricePricePercentPercentConfig() { } + + public ReplacePricePricePercentPercentConfig( + ReplacePricePricePercentPercentConfig replacePricePricePercentPercentConfig + ) + : base(replacePricePricePercentPercentConfig) { } + + public ReplacePricePricePercentPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePricePercentPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class ReplacePricePricePercentPercentConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePricePercentPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReplacePricePricePercentConversionRateConfigConverter))] +public record class ReplacePricePricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePricePercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePricePercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePricePercentConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePricePercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ReplacePricePriceEventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required ReplacePricePriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public ReplacePricePriceEventOutput(ReplacePricePriceEventOutput replacePricePriceEventOutput) + : base(replacePricePriceEventOutput) { } + + public ReplacePricePriceEventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceEventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceEventOutputFromRaw : IFromRawJson +{ + /// + public ReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceEventOutputCadenceConverter))] +public enum ReplacePricePriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceEventOutputCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceEventOutputCadence.Annual, + "semi_annual" => ReplacePricePriceEventOutputCadence.SemiAnnual, + "monthly" => ReplacePricePriceEventOutputCadence.Monthly, + "quarterly" => ReplacePricePriceEventOutputCadence.Quarterly, + "one_time" => ReplacePricePriceEventOutputCadence.OneTime, + "custom" => ReplacePricePriceEventOutputCadence.Custom, + _ => (ReplacePricePriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceEventOutputCadence.Annual => "annual", + ReplacePricePriceEventOutputCadence.SemiAnnual => "semi_annual", + ReplacePricePriceEventOutputCadence.Monthly => "monthly", + ReplacePricePriceEventOutputCadence.Quarterly => "quarterly", + ReplacePricePriceEventOutputCadence.OneTime => "one_time", + ReplacePricePriceEventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceEventOutputEventOutputConfig, + ReplacePricePriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceEventOutputEventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public ReplacePricePriceEventOutputEventOutputConfig() { } + + public ReplacePricePriceEventOutputEventOutputConfig( + ReplacePricePriceEventOutputEventOutputConfig replacePricePriceEventOutputEventOutputConfig + ) + : base(replacePricePriceEventOutputEventOutputConfig) { } + + public ReplacePricePriceEventOutputEventOutputConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceEventOutputEventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceEventOutputEventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class ReplacePricePriceEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceEventOutputEventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReplacePricePriceEventOutputConversionRateConfigConverter))] +public record class ReplacePricePriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceEventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePriceEventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceEventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustment.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustment.cs deleted file mode 100644 index 66953216..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustment.cs +++ /dev/null @@ -1,73 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddAdjustmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the plan. - /// - public required AddAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this adjustment to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.PlanPhaseOrder; - } - - public AddAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustmentProperties/Adjustment.cs deleted file mode 100644 index b5dcbf0c..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the plan. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index d2905a64..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPrice.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPrice.cs deleted file mode 100644 index 01aaf8b2..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPrice.cs +++ /dev/null @@ -1,88 +0,0 @@ -using AddPriceProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddPriceProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddPrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The allocation price to add to the plan. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The phase to add this price to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The price to add to the plan - /// - public AddPriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.AllocationPrice?.Validate(); - _ = this.PlanPhaseOrder; - this.Price?.Validate(); - } - - public AddPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPriceProperties/Price.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPriceProperties/Price.cs deleted file mode 100644 index 401cec51..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPriceProperties/Price.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddPriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddPriceProperties; - -/// -/// The price to add to the plan -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewPlanUnitPrice Create(Models::NewPlanUnitPrice value) => - new(value); - - public static PriceVariants::NewPlanPackagePrice Create(Models::NewPlanPackagePrice value) => - new(value); - - public static PriceVariants::NewPlanMatrixPrice Create(Models::NewPlanMatrixPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredPrice Create(Models::NewPlanTieredPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredBPSPrice Create( - Models::NewPlanTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewPlanBPSPrice Create(Models::NewPlanBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkBPSPrice Create(Models::NewPlanBulkBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkPrice Create(Models::NewPlanBulkPrice value) => - new(value); - - public static PriceVariants::NewPlanThresholdTotalAmountPrice Create( - Models::NewPlanThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackagePrice Create( - Models::NewPlanTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredWithMinimumPrice Create( - Models::NewPlanTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithPercentPrice Create( - Models::NewPlanUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewPlanPackageWithAllocationPrice Create( - Models::NewPlanPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanTierWithProrationPrice Create( - Models::NewPlanTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithProrationPrice Create( - Models::NewPlanUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedAllocationPrice Create( - Models::NewPlanGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithProratedMinimumPrice Create( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithMeteredMinimumPrice Create( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithDisplayNamePrice Create( - Models::NewPlanMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewPlanBulkWithProrationPrice Create( - Models::NewPlanBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPackagePrice Create( - Models::NewPlanGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanMaxGroupTieredPackagePrice Create( - Models::NewPlanMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithUnitPricingPrice Create( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithTieredPricingPrice Create( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanCumulativeGroupedBulkPrice Create( - Models::NewPlanCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackageWithMinimumPrice Create( - Models::NewPlanTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithAllocationPrice Create( - Models::NewPlanMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPrice Create( - Models::NewPlanGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPriceProperties/PriceVariants/All.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPriceProperties/PriceVariants/All.cs deleted file mode 100644 index eec0251e..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/AddPriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,634 +0,0 @@ -using AddPriceProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddPriceProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.AddPriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitPrice(Models::NewPlanUnitPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitPrice From(Models::NewPlanUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanPackagePrice(Models::NewPlanPackagePrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackagePrice From(Models::NewPlanPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanMatrixPrice(Models::NewPlanMatrixPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixPrice From(Models::NewPlanMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPrice(Models::NewPlanTieredPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPrice From(Models::NewPlanTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredBPSPrice(Models::NewPlanTieredBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredBPSPrice From(Models::NewPlanTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBPSPrice(Models::NewPlanBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBPSPrice From(Models::NewPlanBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkBPSPrice(Models::NewPlanBulkBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkBPSPrice From(Models::NewPlanBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkPrice(Models::NewPlanBulkPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkPrice From(Models::NewPlanBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanThresholdTotalAmountPrice, - Models::NewPlanThresholdTotalAmountPrice - >) -)] -public sealed record class NewPlanThresholdTotalAmountPrice( - Models::NewPlanThresholdTotalAmountPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanThresholdTotalAmountPrice From( - Models::NewPlanThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPackagePrice(Models::NewPlanTieredPackagePrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPackagePrice From(Models::NewPlanTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredWithMinimumPrice, - Models::NewPlanTieredWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredWithMinimumPrice( - Models::NewPlanTieredWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredWithMinimumPrice From(Models::NewPlanTieredWithMinimumPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitWithPercentPrice(Models::NewPlanUnitWithPercentPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithPercentPrice From(Models::NewPlanUnitWithPercentPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanPackageWithAllocationPrice, - Models::NewPlanPackageWithAllocationPrice - >) -)] -public sealed record class NewPlanPackageWithAllocationPrice( - Models::NewPlanPackageWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackageWithAllocationPrice From( - Models::NewPlanPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTierWithProrationPrice, - Models::NewPlanTierWithProrationPrice - >) -)] -public sealed record class NewPlanTierWithProrationPrice( - Models::NewPlanTierWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTierWithProrationPrice From(Models::NewPlanTierWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanUnitWithProrationPrice, - Models::NewPlanUnitWithProrationPrice - >) -)] -public sealed record class NewPlanUnitWithProrationPrice( - Models::NewPlanUnitWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithProrationPrice From(Models::NewPlanUnitWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedAllocationPrice, - Models::NewPlanGroupedAllocationPrice - >) -)] -public sealed record class NewPlanGroupedAllocationPrice( - Models::NewPlanGroupedAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedAllocationPrice From(Models::NewPlanGroupedAllocationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithProratedMinimumPrice( - Models::NewPlanGroupedWithProratedMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - > -{ - public static NewPlanGroupedWithProratedMinimumPrice From( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithMeteredMinimumPrice( - Models::NewPlanGroupedWithMeteredMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - > -{ - public static NewPlanGroupedWithMeteredMinimumPrice From( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithDisplayNamePrice, - Models::NewPlanMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewPlanMatrixWithDisplayNamePrice( - Models::NewPlanMatrixWithDisplayNamePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithDisplayNamePrice From( - Models::NewPlanMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanBulkWithProrationPrice, - Models::NewPlanBulkWithProrationPrice - >) -)] -public sealed record class NewPlanBulkWithProrationPrice( - Models::NewPlanBulkWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkWithProrationPrice From(Models::NewPlanBulkWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedTieredPackagePrice, - Models::NewPlanGroupedTieredPackagePrice - >) -)] -public sealed record class NewPlanGroupedTieredPackagePrice( - Models::NewPlanGroupedTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPackagePrice From( - Models::NewPlanGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMaxGroupTieredPackagePrice, - Models::NewPlanMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewPlanMaxGroupTieredPackagePrice( - Models::NewPlanMaxGroupTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMaxGroupTieredPackagePrice From( - Models::NewPlanMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithUnitPricingPrice( - Models::NewPlanScalableMatrixWithUnitPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - > -{ - public static NewPlanScalableMatrixWithUnitPricingPrice From( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithTieredPricingPrice( - Models::NewPlanScalableMatrixWithTieredPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - > -{ - public static NewPlanScalableMatrixWithTieredPricingPrice From( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanCumulativeGroupedBulkPrice, - Models::NewPlanCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewPlanCumulativeGroupedBulkPrice( - Models::NewPlanCumulativeGroupedBulkPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanCumulativeGroupedBulkPrice From( - Models::NewPlanCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredPackageWithMinimumPrice( - Models::NewPlanTieredPackageWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - > -{ - public static NewPlanTieredPackageWithMinimumPrice From( - Models::NewPlanTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithAllocationPrice, - Models::NewPlanMatrixWithAllocationPrice - >) -)] -public sealed record class NewPlanMatrixWithAllocationPrice( - Models::NewPlanMatrixWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithAllocationPrice From( - Models::NewPlanMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanGroupedTieredPrice(Models::NewPlanGroupedTieredPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPrice From(Models::NewPlanGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/RemoveAdjustment.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/RemoveAdjustment.cs deleted file mode 100644 index a8cb7ba3..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/RemoveAdjustment.cs +++ /dev/null @@ -1,72 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemoveAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the adjustment to remove from on the plan. - /// - public required string AdjustmentID - { - get - { - if (!this.Properties.TryGetValue("adjustment_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_id"); - } - set { this.Properties["adjustment_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to remove this adjustment from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.AdjustmentID; - _ = this.PlanPhaseOrder; - } - - public RemoveAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemoveAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemoveAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/RemovePrice.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/RemovePrice.cs deleted file mode 100644 index 02f8cf32..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/RemovePrice.cs +++ /dev/null @@ -1,72 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemovePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price to remove from the plan. - /// - public required string PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to remove this price from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.PriceID; - _ = this.PlanPhaseOrder; - } - - public RemovePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemovePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemovePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustment.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustment.cs deleted file mode 100644 index 82739022..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustment.cs +++ /dev/null @@ -1,104 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplaceAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the plan. - /// - public required ReplaceAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the adjustment on the plan to replace in the plan. - /// - public required string ReplacesAdjustmentID - { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_adjustment_id"); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The phase to replace this adjustment from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.ReplacesAdjustmentID; - _ = this.PlanPhaseOrder; - } - - public ReplaceAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplaceAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplaceAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs deleted file mode 100644 index 342e9fb1..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the plan. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 28a66996..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePrice.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePrice.cs deleted file mode 100644 index b4c57994..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePrice.cs +++ /dev/null @@ -1,112 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplacePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price on the plan to replace in the plan. - /// - public required string ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_price_id"); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The allocation price to add to the plan. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The phase to replace this price from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The price to add to the plan - /// - public ReplacePriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ReplacesPriceID; - this.AllocationPrice?.Validate(); - _ = this.PlanPhaseOrder; - this.Price?.Validate(); - } - - public ReplacePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplacePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplacePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePriceProperties/Price.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePriceProperties/Price.cs deleted file mode 100644 index 237330c7..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePriceProperties/Price.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplacePriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplacePriceProperties; - -/// -/// The price to add to the plan -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewPlanUnitPrice Create(Models::NewPlanUnitPrice value) => - new(value); - - public static PriceVariants::NewPlanPackagePrice Create(Models::NewPlanPackagePrice value) => - new(value); - - public static PriceVariants::NewPlanMatrixPrice Create(Models::NewPlanMatrixPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredPrice Create(Models::NewPlanTieredPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredBPSPrice Create( - Models::NewPlanTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewPlanBPSPrice Create(Models::NewPlanBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkBPSPrice Create(Models::NewPlanBulkBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkPrice Create(Models::NewPlanBulkPrice value) => - new(value); - - public static PriceVariants::NewPlanThresholdTotalAmountPrice Create( - Models::NewPlanThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackagePrice Create( - Models::NewPlanTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredWithMinimumPrice Create( - Models::NewPlanTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithPercentPrice Create( - Models::NewPlanUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewPlanPackageWithAllocationPrice Create( - Models::NewPlanPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanTierWithProrationPrice Create( - Models::NewPlanTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithProrationPrice Create( - Models::NewPlanUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedAllocationPrice Create( - Models::NewPlanGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithProratedMinimumPrice Create( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithMeteredMinimumPrice Create( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithDisplayNamePrice Create( - Models::NewPlanMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewPlanBulkWithProrationPrice Create( - Models::NewPlanBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPackagePrice Create( - Models::NewPlanGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanMaxGroupTieredPackagePrice Create( - Models::NewPlanMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithUnitPricingPrice Create( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithTieredPricingPrice Create( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanCumulativeGroupedBulkPrice Create( - Models::NewPlanCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackageWithMinimumPrice Create( - Models::NewPlanTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithAllocationPrice Create( - Models::NewPlanMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPrice Create( - Models::NewPlanGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePriceProperties/PriceVariants/All.cs b/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePriceProperties/PriceVariants/All.cs deleted file mode 100644 index 1a916bd4..00000000 --- a/src/Orb/Models/Beta/BetaCreatePlanVersionParamsProperties/ReplacePriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,634 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.BetaCreatePlanVersionParamsProperties.ReplacePriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitPrice(Models::NewPlanUnitPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitPrice From(Models::NewPlanUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanPackagePrice(Models::NewPlanPackagePrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackagePrice From(Models::NewPlanPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanMatrixPrice(Models::NewPlanMatrixPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixPrice From(Models::NewPlanMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPrice(Models::NewPlanTieredPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPrice From(Models::NewPlanTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredBPSPrice(Models::NewPlanTieredBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredBPSPrice From(Models::NewPlanTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBPSPrice(Models::NewPlanBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBPSPrice From(Models::NewPlanBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkBPSPrice(Models::NewPlanBulkBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkBPSPrice From(Models::NewPlanBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkPrice(Models::NewPlanBulkPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkPrice From(Models::NewPlanBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanThresholdTotalAmountPrice, - Models::NewPlanThresholdTotalAmountPrice - >) -)] -public sealed record class NewPlanThresholdTotalAmountPrice( - Models::NewPlanThresholdTotalAmountPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanThresholdTotalAmountPrice From( - Models::NewPlanThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPackagePrice(Models::NewPlanTieredPackagePrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPackagePrice From(Models::NewPlanTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredWithMinimumPrice, - Models::NewPlanTieredWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredWithMinimumPrice( - Models::NewPlanTieredWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredWithMinimumPrice From(Models::NewPlanTieredWithMinimumPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitWithPercentPrice(Models::NewPlanUnitWithPercentPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithPercentPrice From(Models::NewPlanUnitWithPercentPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanPackageWithAllocationPrice, - Models::NewPlanPackageWithAllocationPrice - >) -)] -public sealed record class NewPlanPackageWithAllocationPrice( - Models::NewPlanPackageWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackageWithAllocationPrice From( - Models::NewPlanPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTierWithProrationPrice, - Models::NewPlanTierWithProrationPrice - >) -)] -public sealed record class NewPlanTierWithProrationPrice( - Models::NewPlanTierWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTierWithProrationPrice From(Models::NewPlanTierWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanUnitWithProrationPrice, - Models::NewPlanUnitWithProrationPrice - >) -)] -public sealed record class NewPlanUnitWithProrationPrice( - Models::NewPlanUnitWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithProrationPrice From(Models::NewPlanUnitWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedAllocationPrice, - Models::NewPlanGroupedAllocationPrice - >) -)] -public sealed record class NewPlanGroupedAllocationPrice( - Models::NewPlanGroupedAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedAllocationPrice From(Models::NewPlanGroupedAllocationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithProratedMinimumPrice( - Models::NewPlanGroupedWithProratedMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - > -{ - public static NewPlanGroupedWithProratedMinimumPrice From( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithMeteredMinimumPrice( - Models::NewPlanGroupedWithMeteredMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - > -{ - public static NewPlanGroupedWithMeteredMinimumPrice From( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithDisplayNamePrice, - Models::NewPlanMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewPlanMatrixWithDisplayNamePrice( - Models::NewPlanMatrixWithDisplayNamePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithDisplayNamePrice From( - Models::NewPlanMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanBulkWithProrationPrice, - Models::NewPlanBulkWithProrationPrice - >) -)] -public sealed record class NewPlanBulkWithProrationPrice( - Models::NewPlanBulkWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkWithProrationPrice From(Models::NewPlanBulkWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedTieredPackagePrice, - Models::NewPlanGroupedTieredPackagePrice - >) -)] -public sealed record class NewPlanGroupedTieredPackagePrice( - Models::NewPlanGroupedTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPackagePrice From( - Models::NewPlanGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMaxGroupTieredPackagePrice, - Models::NewPlanMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewPlanMaxGroupTieredPackagePrice( - Models::NewPlanMaxGroupTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMaxGroupTieredPackagePrice From( - Models::NewPlanMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithUnitPricingPrice( - Models::NewPlanScalableMatrixWithUnitPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - > -{ - public static NewPlanScalableMatrixWithUnitPricingPrice From( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithTieredPricingPrice( - Models::NewPlanScalableMatrixWithTieredPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - > -{ - public static NewPlanScalableMatrixWithTieredPricingPrice From( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanCumulativeGroupedBulkPrice, - Models::NewPlanCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewPlanCumulativeGroupedBulkPrice( - Models::NewPlanCumulativeGroupedBulkPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanCumulativeGroupedBulkPrice From( - Models::NewPlanCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredPackageWithMinimumPrice( - Models::NewPlanTieredPackageWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - > -{ - public static NewPlanTieredPackageWithMinimumPrice From( - Models::NewPlanTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithAllocationPrice, - Models::NewPlanMatrixWithAllocationPrice - >) -)] -public sealed record class NewPlanMatrixWithAllocationPrice( - Models::NewPlanMatrixWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithAllocationPrice From( - Models::NewPlanMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanGroupedTieredPrice(Models::NewPlanGroupedTieredPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPrice From(Models::NewPlanGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/BetaFetchPlanVersionParams.cs b/src/Orb/Models/Beta/BetaFetchPlanVersionParams.cs index 8e9be346..22bee712 100644 --- a/src/Orb/Models/Beta/BetaFetchPlanVersionParams.cs +++ b/src/Orb/Models/Beta/BetaFetchPlanVersionParams.cs @@ -1,39 +1,78 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Beta; /// -/// This API endpoint is in beta and its interface may change. It is recommended for -/// use only in test mode. -/// /// This endpoint is used to fetch a plan version. It returns the phases, prices, /// and adjustments present on this version of the plan. /// -public sealed record class BetaFetchPlanVersionParams : Orb::ParamsBase +public sealed record class BetaFetchPlanVersionParams : ParamsBase { - public required string PlanID; + public required string PlanID { get; init; } - public required string Version; + public string? Version { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public BetaFetchPlanVersionParams() { } + + public BetaFetchPlanVersionParams(BetaFetchPlanVersionParams betaFetchPlanVersionParams) + : base(betaFetchPlanVersionParams) { } + + public BetaFetchPlanVersionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BetaFetchPlanVersionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static BetaFetchPlanVersionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/{0}/versions/{1}", this.PlanID, this.Version) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Beta/BetaSetDefaultPlanVersionParams.cs b/src/Orb/Models/Beta/BetaSetDefaultPlanVersionParams.cs index 2347b29e..ee7a5859 100644 --- a/src/Orb/Models/Beta/BetaSetDefaultPlanVersionParams.cs +++ b/src/Orb/Models/Beta/BetaSetDefaultPlanVersionParams.cs @@ -1,68 +1,111 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Beta; /// -/// This API endpoint is in beta and its interface may change. It is recommended for -/// use only in test mode. -/// /// This endpoint allows setting the default version of a plan. /// -public sealed record class BetaSetDefaultPlanVersionParams : Orb::ParamsBase +public sealed record class BetaSetDefaultPlanVersionParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string PlanID; + public string? PlanID { get; init; } /// /// Plan version to set as the default. /// public required long Version { - get - { - if (!this.BodyProperties.TryGetValue("version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "version", - "Missing required argument" - ); + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "version"); } + init { JsonModel.Set(this._rawBodyData, "version", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["version"] = Json::JsonSerializer.SerializeToElement(value); } + public BetaSetDefaultPlanVersionParams() { } + + public BetaSetDefaultPlanVersionParams( + BetaSetDefaultPlanVersionParams betaSetDefaultPlanVersionParams + ) + : base(betaSetDefaultPlanVersionParams) + { + this._rawBodyData = [.. betaSetDefaultPlanVersionParams._rawBodyData]; + } + + public BetaSetDefaultPlanVersionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BetaSetDefaultPlanVersionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static BetaSetDefaultPlanVersionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/{0}/set_default_version", this.PlanID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParams.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParams.cs index a9921896..a208c41f 100644 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParams.cs +++ b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParams.cs @@ -1,218 +1,16829 @@ -using ExternalPlanIDCreatePlanVersionParamsProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Beta.ExternalPlanID; /// -/// This API endpoint is in beta and its interface may change. It is recommended for -/// use only in test mode. -/// /// This endpoint allows the creation of a new plan version for an existing plan. /// -public sealed record class ExternalPlanIDCreatePlanVersionParams : Orb::ParamsBase +public sealed record class ExternalPlanIDCreatePlanVersionParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ExternalPlanID; + public string? ExternalPlanID { get; init; } /// /// New version number. /// public required long Version { - get - { - if (!this.BodyProperties.TryGetValue("version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "version", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["version"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "version"); } + init { JsonModel.Set(this._rawBodyData, "version", value); } } /// /// Additional adjustments to be added to the plan. /// - public Generic::List? AddAdjustments + public IReadOnlyList? AddAdjustments { get { - if (!this.BodyProperties.TryGetValue("add_adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["add_adjustments"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "add_adjustments"); } + init { JsonModel.Set(this._rawBodyData, "add_adjustments", value); } } /// /// Additional prices to be added to the plan. /// - public Generic::List? AddPrices + public IReadOnlyList? AddPrices { get { - if (!this.BodyProperties.TryGetValue("add_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "add_prices"); } - set { this.BodyProperties["add_prices"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "add_prices", value); } } /// /// Adjustments to be removed from the plan. /// - public Generic::List? RemoveAdjustments + public IReadOnlyList? RemoveAdjustments { get { - if ( - !this.BodyProperties.TryGetValue( - "remove_adjustments", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["remove_adjustments"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "remove_adjustments"); } + init { JsonModel.Set(this._rawBodyData, "remove_adjustments", value); } } /// /// Prices to be removed from the plan. /// - public Generic::List? RemovePrices + public IReadOnlyList? RemovePrices { get { - if (!this.BodyProperties.TryGetValue("remove_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "remove_prices"); } - set + init { JsonModel.Set(this._rawBodyData, "remove_prices", value); } + } + + /// + /// Adjustments to be replaced with additional adjustments on the plan. + /// + public IReadOnlyList? ReplaceAdjustments + { + get { - this.BodyProperties["remove_prices"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "replace_adjustments"); } + init { JsonModel.Set(this._rawBodyData, "replace_adjustments", value); } } /// - /// Adjustments to be replaced with additional adjustments on the plan. + /// Prices to be replaced with additional prices on the plan. /// - public Generic::List? ReplaceAdjustments + public IReadOnlyList? ReplacePrices { get { - if ( - !this.BodyProperties.TryGetValue( - "replace_adjustments", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "replace_prices"); + } + init { JsonModel.Set(this._rawBodyData, "replace_prices", value); } + } - return Json::JsonSerializer.Deserialize?>( - element - ); + /// + /// Set this new plan version as the default + /// + public bool? SetAsDefault + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "set_as_default"); } + init { JsonModel.Set(this._rawBodyData, "set_as_default", value); } + } + + public ExternalPlanIDCreatePlanVersionParams() { } + + public ExternalPlanIDCreatePlanVersionParams( + ExternalPlanIDCreatePlanVersionParams externalPlanIDCreatePlanVersionParams + ) + : base(externalPlanIDCreatePlanVersionParams) + { + this._rawBodyData = [.. externalPlanIDCreatePlanVersionParams._rawBodyData]; + } + + public ExternalPlanIDCreatePlanVersionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPlanIDCreatePlanVersionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPlanIDCreatePlanVersionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format("/plans/external_plan_id/{0}/versions", this.ExternalPlanID) + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } - set + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.AddAdjustment, + global::Orb.Models.Beta.ExternalPlanID.AddAdjustmentFromRaw + >) +)] +public sealed record class AddAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the plan. + /// + public required global::Orb.Models.Beta.ExternalPlanID.Adjustment Adjustment + { + get { - this.BodyProperties["replace_adjustments"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" ); } + init { JsonModel.Set(this._rawData, "adjustment", value); } } /// - /// Prices to be replaced with additional prices on the plan. + /// The phase to add this adjustment to. /// - public Generic::List? ReplacePrices + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.PlanPhaseOrder; + } + + public AddAdjustment() { } + + public AddAdjustment(global::Orb.Models.Beta.ExternalPlanID.AddAdjustment addAdjustment) + : base(addAdjustment) { } + + public AddAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AddAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.AddAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public AddAdjustment(global::Orb.Models.Beta.ExternalPlanID.Adjustment adjustment) + : this() + { + this.Adjustment = adjustment; + } +} + +class AddAdjustmentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.AddAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.AddAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the plan. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.AdjustmentConverter))] +public record class Adjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency { get { - if (!this.BodyProperties.TryGetValue("replace_prices", out Json::JsonElement element)) - return null; + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } - return Json::JsonSerializer.Deserialize?>( - element + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel ); } - set + } + + public Adjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) { - this.BodyProperties["replace_prices"] = Json::JsonSerializer.SerializeToElement(value); + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); } } /// - /// Set this new plan version as the default + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// /// - public bool? SetAsDefault + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) { - get + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Adjustment"), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Adjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Adjustment( + NewUsageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Adjustment( + NewAmountDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Adjustment( + NewMinimum value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Adjustment( + NewMaximum value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Beta.ExternalPlanID.Adjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentConverter : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.Adjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) { - if (!this.BodyProperties.TryGetValue("set_as_default", out Json::JsonElement element)) - return null; + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } - return Json::JsonSerializer.Deserialize(element); + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.Adjustment(element); + } } - set + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.Adjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.AddPrice, + global::Orb.Models.Beta.ExternalPlanID.AddPriceFromRaw + >) +)] +public sealed record class AddPrice : JsonModel +{ + /// + /// The allocation price to add to the plan. + /// + public NewAllocationPrice? AllocationPrice + { + get { - this.BodyProperties["set_as_default"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); } + init { JsonModel.Set(this._rawData, "allocation_price", value); } } - public override System::Uri Url(Orb::IOrbClient client) + /// + /// The phase to add this price to. + /// + public long? PlanPhaseOrder { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') - + string.Format("/plans/external_plan_id/{0}/versions", this.ExternalPlanID) - ) + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New plan price request body params. + /// + public global::Orb.Models.Beta.ExternalPlanID.Price? Price + { + get { - Query = this.QueryString(client), - }.Uri; + return JsonModel.GetNullableClass( + this.RawData, + "price" + ); + } + init { JsonModel.Set(this._rawData, "price", value); } } - public Http::StringContent BodyContent() + /// + public override void Validate() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this.AllocationPrice?.Validate(); + _ = this.PlanPhaseOrder; + this.Price?.Validate(); + } + + public AddPrice() { } + + public AddPrice(global::Orb.Models.Beta.ExternalPlanID.AddPrice addPrice) + : base(addPrice) { } + + public AddPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AddPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.AddPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AddPriceFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.AddPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.AddPrice.FromRawUnchecked(rawData); +} + +/// +/// New plan price request body params. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.PriceConverter))] +public record class Price +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public string ItemID { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + newPlanUnit: (x) => x.ItemID, + newPlanTiered: (x) => x.ItemID, + newPlanBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newPlanPackage: (x) => x.ItemID, + newPlanMatrix: (x) => x.ItemID, + newPlanThresholdTotalAmount: (x) => x.ItemID, + newPlanTieredPackage: (x) => x.ItemID, + newPlanTieredWithMinimum: (x) => x.ItemID, + newPlanGroupedTiered: (x) => x.ItemID, + newPlanTieredPackageWithMinimum: (x) => x.ItemID, + newPlanPackageWithAllocation: (x) => x.ItemID, + newPlanUnitWithPercent: (x) => x.ItemID, + newPlanMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newPlanUnitWithProration: (x) => x.ItemID, + newPlanGroupedAllocation: (x) => x.ItemID, + newPlanBulkWithProration: (x) => x.ItemID, + newPlanGroupedWithProratedMinimum: (x) => x.ItemID, + newPlanGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newPlanMatrixWithDisplayName: (x) => x.ItemID, + newPlanGroupedTieredPackage: (x) => x.ItemID, + newPlanMaxGroupTieredPackage: (x) => x.ItemID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ItemID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ItemID, + newPlanCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newPlanMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); } } + + public string Name + { + get + { + return Match( + newPlanUnit: (x) => x.Name, + newPlanTiered: (x) => x.Name, + newPlanBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newPlanPackage: (x) => x.Name, + newPlanMatrix: (x) => x.Name, + newPlanThresholdTotalAmount: (x) => x.Name, + newPlanTieredPackage: (x) => x.Name, + newPlanTieredWithMinimum: (x) => x.Name, + newPlanGroupedTiered: (x) => x.Name, + newPlanTieredPackageWithMinimum: (x) => x.Name, + newPlanPackageWithAllocation: (x) => x.Name, + newPlanUnitWithPercent: (x) => x.Name, + newPlanMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newPlanUnitWithProration: (x) => x.Name, + newPlanGroupedAllocation: (x) => x.Name, + newPlanBulkWithProration: (x) => x.Name, + newPlanGroupedWithProratedMinimum: (x) => x.Name, + newPlanGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newPlanMatrixWithDisplayName: (x) => x.Name, + newPlanGroupedTieredPackage: (x) => x.Name, + newPlanMaxGroupTieredPackage: (x) => x.Name, + newPlanScalableMatrixWithUnitPricing: (x) => x.Name, + newPlanScalableMatrixWithTieredPricing: (x) => x.Name, + newPlanCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newPlanMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newPlanUnit: (x) => x.BillableMetricID, + newPlanTiered: (x) => x.BillableMetricID, + newPlanBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newPlanPackage: (x) => x.BillableMetricID, + newPlanMatrix: (x) => x.BillableMetricID, + newPlanThresholdTotalAmount: (x) => x.BillableMetricID, + newPlanTieredPackage: (x) => x.BillableMetricID, + newPlanTieredWithMinimum: (x) => x.BillableMetricID, + newPlanGroupedTiered: (x) => x.BillableMetricID, + newPlanTieredPackageWithMinimum: (x) => x.BillableMetricID, + newPlanPackageWithAllocation: (x) => x.BillableMetricID, + newPlanUnitWithPercent: (x) => x.BillableMetricID, + newPlanMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newPlanUnitWithProration: (x) => x.BillableMetricID, + newPlanGroupedAllocation: (x) => x.BillableMetricID, + newPlanBulkWithProration: (x) => x.BillableMetricID, + newPlanGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newPlanGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newPlanMatrixWithDisplayName: (x) => x.BillableMetricID, + newPlanGroupedTieredPackage: (x) => x.BillableMetricID, + newPlanMaxGroupTieredPackage: (x) => x.BillableMetricID, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newPlanCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newPlanMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newPlanUnit: (x) => x.BilledInAdvance, + newPlanTiered: (x) => x.BilledInAdvance, + newPlanBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newPlanPackage: (x) => x.BilledInAdvance, + newPlanMatrix: (x) => x.BilledInAdvance, + newPlanThresholdTotalAmount: (x) => x.BilledInAdvance, + newPlanTieredPackage: (x) => x.BilledInAdvance, + newPlanTieredWithMinimum: (x) => x.BilledInAdvance, + newPlanGroupedTiered: (x) => x.BilledInAdvance, + newPlanTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newPlanPackageWithAllocation: (x) => x.BilledInAdvance, + newPlanUnitWithPercent: (x) => x.BilledInAdvance, + newPlanMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newPlanUnitWithProration: (x) => x.BilledInAdvance, + newPlanGroupedAllocation: (x) => x.BilledInAdvance, + newPlanBulkWithProration: (x) => x.BilledInAdvance, + newPlanGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newPlanGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newPlanMatrixWithDisplayName: (x) => x.BilledInAdvance, + newPlanGroupedTieredPackage: (x) => x.BilledInAdvance, + newPlanMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newPlanCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newPlanMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.BillingCycleConfiguration, + newPlanTiered: (x) => x.BillingCycleConfiguration, + newPlanBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newPlanPackage: (x) => x.BillingCycleConfiguration, + newPlanMatrix: (x) => x.BillingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newPlanTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedTiered: (x) => x.BillingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newPlanUnitWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanBulkWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newPlanUnit: (x) => x.ConversionRate, + newPlanTiered: (x) => x.ConversionRate, + newPlanBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newPlanPackage: (x) => x.ConversionRate, + newPlanMatrix: (x) => x.ConversionRate, + newPlanThresholdTotalAmount: (x) => x.ConversionRate, + newPlanTieredPackage: (x) => x.ConversionRate, + newPlanTieredWithMinimum: (x) => x.ConversionRate, + newPlanGroupedTiered: (x) => x.ConversionRate, + newPlanTieredPackageWithMinimum: (x) => x.ConversionRate, + newPlanPackageWithAllocation: (x) => x.ConversionRate, + newPlanUnitWithPercent: (x) => x.ConversionRate, + newPlanMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newPlanUnitWithProration: (x) => x.ConversionRate, + newPlanGroupedAllocation: (x) => x.ConversionRate, + newPlanBulkWithProration: (x) => x.ConversionRate, + newPlanGroupedWithProratedMinimum: (x) => x.ConversionRate, + newPlanGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newPlanMatrixWithDisplayName: (x) => x.ConversionRate, + newPlanGroupedTieredPackage: (x) => x.ConversionRate, + newPlanMaxGroupTieredPackage: (x) => x.ConversionRate, + newPlanScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newPlanScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newPlanCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newPlanMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newPlanUnit: (x) => x.Currency, + newPlanTiered: (x) => x.Currency, + newPlanBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newPlanPackage: (x) => x.Currency, + newPlanMatrix: (x) => x.Currency, + newPlanThresholdTotalAmount: (x) => x.Currency, + newPlanTieredPackage: (x) => x.Currency, + newPlanTieredWithMinimum: (x) => x.Currency, + newPlanGroupedTiered: (x) => x.Currency, + newPlanTieredPackageWithMinimum: (x) => x.Currency, + newPlanPackageWithAllocation: (x) => x.Currency, + newPlanUnitWithPercent: (x) => x.Currency, + newPlanMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newPlanUnitWithProration: (x) => x.Currency, + newPlanGroupedAllocation: (x) => x.Currency, + newPlanBulkWithProration: (x) => x.Currency, + newPlanGroupedWithProratedMinimum: (x) => x.Currency, + newPlanGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newPlanMatrixWithDisplayName: (x) => x.Currency, + newPlanGroupedTieredPackage: (x) => x.Currency, + newPlanMaxGroupTieredPackage: (x) => x.Currency, + newPlanScalableMatrixWithUnitPricing: (x) => x.Currency, + newPlanScalableMatrixWithTieredPricing: (x) => x.Currency, + newPlanCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newPlanMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.DimensionalPriceConfiguration, + newPlanTiered: (x) => x.DimensionalPriceConfiguration, + newPlanBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newPlanPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMatrix: (x) => x.DimensionalPriceConfiguration, + newPlanThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newPlanUnit: (x) => x.ExternalPriceID, + newPlanTiered: (x) => x.ExternalPriceID, + newPlanBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newPlanPackage: (x) => x.ExternalPriceID, + newPlanMatrix: (x) => x.ExternalPriceID, + newPlanThresholdTotalAmount: (x) => x.ExternalPriceID, + newPlanTieredPackage: (x) => x.ExternalPriceID, + newPlanTieredWithMinimum: (x) => x.ExternalPriceID, + newPlanGroupedTiered: (x) => x.ExternalPriceID, + newPlanTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newPlanPackageWithAllocation: (x) => x.ExternalPriceID, + newPlanUnitWithPercent: (x) => x.ExternalPriceID, + newPlanMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newPlanUnitWithProration: (x) => x.ExternalPriceID, + newPlanGroupedAllocation: (x) => x.ExternalPriceID, + newPlanBulkWithProration: (x) => x.ExternalPriceID, + newPlanGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newPlanMatrixWithDisplayName: (x) => x.ExternalPriceID, + newPlanGroupedTieredPackage: (x) => x.ExternalPriceID, + newPlanMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newPlanCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newPlanMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newPlanUnit: (x) => x.FixedPriceQuantity, + newPlanTiered: (x) => x.FixedPriceQuantity, + newPlanBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newPlanPackage: (x) => x.FixedPriceQuantity, + newPlanMatrix: (x) => x.FixedPriceQuantity, + newPlanThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newPlanTieredPackage: (x) => x.FixedPriceQuantity, + newPlanTieredWithMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedTiered: (x) => x.FixedPriceQuantity, + newPlanTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newPlanPackageWithAllocation: (x) => x.FixedPriceQuantity, + newPlanUnitWithPercent: (x) => x.FixedPriceQuantity, + newPlanMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newPlanUnitWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanBulkWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newPlanMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newPlanGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newPlanMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newPlanCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newPlanUnit: (x) => x.InvoiceGroupingKey, + newPlanTiered: (x) => x.InvoiceGroupingKey, + newPlanBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newPlanPackage: (x) => x.InvoiceGroupingKey, + newPlanMatrix: (x) => x.InvoiceGroupingKey, + newPlanThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newPlanTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedTiered: (x) => x.InvoiceGroupingKey, + newPlanTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newPlanUnitWithPercent: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newPlanUnitWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanBulkWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newPlanGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newPlanCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.InvoicingCycleConfiguration, + newPlanTiered: (x) => x.InvoicingCycleConfiguration, + newPlanBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newPlanPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMatrix: (x) => x.InvoicingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newPlanUnit: (x) => x.ReferenceID, + newPlanTiered: (x) => x.ReferenceID, + newPlanBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newPlanPackage: (x) => x.ReferenceID, + newPlanMatrix: (x) => x.ReferenceID, + newPlanThresholdTotalAmount: (x) => x.ReferenceID, + newPlanTieredPackage: (x) => x.ReferenceID, + newPlanTieredWithMinimum: (x) => x.ReferenceID, + newPlanGroupedTiered: (x) => x.ReferenceID, + newPlanTieredPackageWithMinimum: (x) => x.ReferenceID, + newPlanPackageWithAllocation: (x) => x.ReferenceID, + newPlanUnitWithPercent: (x) => x.ReferenceID, + newPlanMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newPlanUnitWithProration: (x) => x.ReferenceID, + newPlanGroupedAllocation: (x) => x.ReferenceID, + newPlanBulkWithProration: (x) => x.ReferenceID, + newPlanGroupedWithProratedMinimum: (x) => x.ReferenceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newPlanMatrixWithDisplayName: (x) => x.ReferenceID, + newPlanGroupedTieredPackage: (x) => x.ReferenceID, + newPlanMaxGroupTieredPackage: (x) => x.ReferenceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newPlanCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newPlanMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public Price(NewPlanUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.ExternalPlanID.TieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanScalableMatrixWithUnitPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanScalableMatrixWithTieredPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewPlanMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Beta.ExternalPlanID.Percent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Beta.ExternalPlanID.EventOutput value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnit(out var value)) { + /// // `value` is of type `NewPlanUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnit([NotNullWhen(true)] out NewPlanUnitPrice? value) + { + value = this.Value as NewPlanUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTiered(out var value)) { + /// // `value` is of type `NewPlanTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTiered([NotNullWhen(true)] out NewPlanTieredPrice? value) + { + value = this.Value as NewPlanTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulk(out var value)) { + /// // `value` is of type `NewPlanBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulk([NotNullWhen(true)] out NewPlanBulkPrice? value) + { + value = this.Value as NewPlanBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackage(out var value)) { + /// // `value` is of type `NewPlanPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackage([NotNullWhen(true)] out NewPlanPackagePrice? value) + { + value = this.Value as NewPlanPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrix(out var value)) { + /// // `value` is of type `NewPlanMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrix([NotNullWhen(true)] out NewPlanMatrixPrice? value) + { + value = this.Value as NewPlanMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewPlanThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanThresholdTotalAmount( + [NotNullWhen(true)] out NewPlanThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewPlanThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackage(out var value)) { + /// // `value` is of type `NewPlanTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackage( + [NotNullWhen(true)] out NewPlanTieredPackagePrice? value + ) + { + value = this.Value as NewPlanTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredWithMinimum( + [NotNullWhen(true)] out NewPlanTieredWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTiered(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTiered( + [NotNullWhen(true)] out NewPlanGroupedTieredPrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackageWithMinimum( + [NotNullWhen(true)] out NewPlanTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackageWithAllocation(out var value)) { + /// // `value` is of type `NewPlanPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackageWithAllocation( + [NotNullWhen(true)] out NewPlanPackageWithAllocationPrice? value + ) + { + value = this.Value as NewPlanPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithPercent(out var value)) { + /// // `value` is of type `NewPlanUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithPercent( + [NotNullWhen(true)] out NewPlanUnitWithPercentPrice? value + ) + { + value = this.Value as NewPlanUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewPlanMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithAllocation( + [NotNullWhen(true)] out NewPlanMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewPlanMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.TieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] out global::Orb.Models.Beta.ExternalPlanID.TieredWithProration? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.TieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithProration(out var value)) { + /// // `value` is of type `NewPlanUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithProration( + [NotNullWhen(true)] out NewPlanUnitWithProrationPrice? value + ) + { + value = this.Value as NewPlanUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedAllocation(out var value)) { + /// // `value` is of type `NewPlanGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedAllocation( + [NotNullWhen(true)] out NewPlanGroupedAllocationPrice? value + ) + { + value = this.Value as NewPlanGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulkWithProration(out var value)) { + /// // `value` is of type `NewPlanBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulkWithProration( + [NotNullWhen(true)] out NewPlanBulkWithProrationPrice? value + ) + { + value = this.Value as NewPlanBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewPlanMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithDisplayName( + [NotNullWhen(true)] out NewPlanMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewPlanMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTieredPackage( + [NotNullWhen(true)] out NewPlanGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewPlanMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMaxGroupTieredPackage( + [NotNullWhen(true)] out NewPlanMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewPlanMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewPlanCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanCumulativeGroupedBulk( + [NotNullWhen(true)] out NewPlanCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewPlanCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMinimumComposite(out var value)) { + /// // `value` is of type `NewPlanMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMinimumComposite( + [NotNullWhen(true)] out NewPlanMinimumCompositePrice? value + ) + { + value = this.Value as NewPlanMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.Percent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent( + [NotNullWhen(true)] out global::Orb.Models.Beta.ExternalPlanID.Percent? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.Percent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.EventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] out global::Orb.Models.Beta.ExternalPlanID.EventOutput? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.EventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.TieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.Percent value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.EventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPlanUnit, + System::Action newPlanTiered, + System::Action newPlanBulk, + System::Action bulkWithFilters, + System::Action newPlanPackage, + System::Action newPlanMatrix, + System::Action newPlanThresholdTotalAmount, + System::Action newPlanTieredPackage, + System::Action newPlanTieredWithMinimum, + System::Action newPlanGroupedTiered, + System::Action newPlanTieredPackageWithMinimum, + System::Action newPlanPackageWithAllocation, + System::Action newPlanUnitWithPercent, + System::Action newPlanMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newPlanUnitWithProration, + System::Action newPlanGroupedAllocation, + System::Action newPlanBulkWithProration, + System::Action newPlanGroupedWithProratedMinimum, + System::Action newPlanGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newPlanMatrixWithDisplayName, + System::Action newPlanGroupedTieredPackage, + System::Action newPlanMaxGroupTieredPackage, + System::Action newPlanScalableMatrixWithUnitPricing, + System::Action newPlanScalableMatrixWithTieredPricing, + System::Action newPlanCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newPlanMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewPlanUnitPrice value: + newPlanUnit(value); + break; + case NewPlanTieredPrice value: + newPlanTiered(value); + break; + case NewPlanBulkPrice value: + newPlanBulk(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters value: + bulkWithFilters(value); + break; + case NewPlanPackagePrice value: + newPlanPackage(value); + break; + case NewPlanMatrixPrice value: + newPlanMatrix(value); + break; + case NewPlanThresholdTotalAmountPrice value: + newPlanThresholdTotalAmount(value); + break; + case NewPlanTieredPackagePrice value: + newPlanTieredPackage(value); + break; + case NewPlanTieredWithMinimumPrice value: + newPlanTieredWithMinimum(value); + break; + case NewPlanGroupedTieredPrice value: + newPlanGroupedTiered(value); + break; + case NewPlanTieredPackageWithMinimumPrice value: + newPlanTieredPackageWithMinimum(value); + break; + case NewPlanPackageWithAllocationPrice value: + newPlanPackageWithAllocation(value); + break; + case NewPlanUnitWithPercentPrice value: + newPlanUnitWithPercent(value); + break; + case NewPlanMatrixWithAllocationPrice value: + newPlanMatrixWithAllocation(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.TieredWithProration value: + tieredWithProration(value); + break; + case NewPlanUnitWithProrationPrice value: + newPlanUnitWithProration(value); + break; + case NewPlanGroupedAllocationPrice value: + newPlanGroupedAllocation(value); + break; + case NewPlanBulkWithProrationPrice value: + newPlanBulkWithProration(value); + break; + case NewPlanGroupedWithProratedMinimumPrice value: + newPlanGroupedWithProratedMinimum(value); + break; + case NewPlanGroupedWithMeteredMinimumPrice value: + newPlanGroupedWithMeteredMinimum(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewPlanMatrixWithDisplayNamePrice value: + newPlanMatrixWithDisplayName(value); + break; + case NewPlanGroupedTieredPackagePrice value: + newPlanGroupedTieredPackage(value); + break; + case NewPlanMaxGroupTieredPackagePrice value: + newPlanMaxGroupTieredPackage(value); + break; + case NewPlanScalableMatrixWithUnitPricingPrice value: + newPlanScalableMatrixWithUnitPricing(value); + break; + case NewPlanScalableMatrixWithTieredPricingPrice value: + newPlanScalableMatrixWithTieredPricing(value); + break; + case NewPlanCumulativeGroupedBulkPrice value: + newPlanCumulativeGroupedBulk(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewPlanMinimumCompositePrice value: + newPlanMinimumComposite(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.Percent value: + percent(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.EventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.TieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.Percent value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.EventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPlanUnit, + System::Func newPlanTiered, + System::Func newPlanBulk, + System::Func bulkWithFilters, + System::Func newPlanPackage, + System::Func newPlanMatrix, + System::Func newPlanThresholdTotalAmount, + System::Func newPlanTieredPackage, + System::Func newPlanTieredWithMinimum, + System::Func newPlanGroupedTiered, + System::Func newPlanTieredPackageWithMinimum, + System::Func newPlanPackageWithAllocation, + System::Func newPlanUnitWithPercent, + System::Func newPlanMatrixWithAllocation, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.TieredWithProration, + T + > tieredWithProration, + System::Func newPlanUnitWithProration, + System::Func newPlanGroupedAllocation, + System::Func newPlanBulkWithProration, + System::Func newPlanGroupedWithProratedMinimum, + System::Func newPlanGroupedWithMeteredMinimum, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func newPlanMatrixWithDisplayName, + System::Func newPlanGroupedTieredPackage, + System::Func newPlanMaxGroupTieredPackage, + System::Func< + NewPlanScalableMatrixWithUnitPricingPrice, + T + > newPlanScalableMatrixWithUnitPricing, + System::Func< + NewPlanScalableMatrixWithTieredPricingPrice, + T + > newPlanScalableMatrixWithTieredPricing, + System::Func newPlanCumulativeGroupedBulk, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newPlanMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewPlanUnitPrice value => newPlanUnit(value), + NewPlanTieredPrice value => newPlanTiered(value), + NewPlanBulkPrice value => newPlanBulk(value), + global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters value => bulkWithFilters(value), + NewPlanPackagePrice value => newPlanPackage(value), + NewPlanMatrixPrice value => newPlanMatrix(value), + NewPlanThresholdTotalAmountPrice value => newPlanThresholdTotalAmount(value), + NewPlanTieredPackagePrice value => newPlanTieredPackage(value), + NewPlanTieredWithMinimumPrice value => newPlanTieredWithMinimum(value), + NewPlanGroupedTieredPrice value => newPlanGroupedTiered(value), + NewPlanTieredPackageWithMinimumPrice value => newPlanTieredPackageWithMinimum(value), + NewPlanPackageWithAllocationPrice value => newPlanPackageWithAllocation(value), + NewPlanUnitWithPercentPrice value => newPlanUnitWithPercent(value), + NewPlanMatrixWithAllocationPrice value => newPlanMatrixWithAllocation(value), + global::Orb.Models.Beta.ExternalPlanID.TieredWithProration value => tieredWithProration( + value + ), + NewPlanUnitWithProrationPrice value => newPlanUnitWithProration(value), + NewPlanGroupedAllocationPrice value => newPlanGroupedAllocation(value), + NewPlanBulkWithProrationPrice value => newPlanBulkWithProration(value), + NewPlanGroupedWithProratedMinimumPrice value => newPlanGroupedWithProratedMinimum( + value + ), + NewPlanGroupedWithMeteredMinimumPrice value => newPlanGroupedWithMeteredMinimum(value), + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewPlanMatrixWithDisplayNamePrice value => newPlanMatrixWithDisplayName(value), + NewPlanGroupedTieredPackagePrice value => newPlanGroupedTieredPackage(value), + NewPlanMaxGroupTieredPackagePrice value => newPlanMaxGroupTieredPackage(value), + NewPlanScalableMatrixWithUnitPricingPrice value => newPlanScalableMatrixWithUnitPricing( + value + ), + NewPlanScalableMatrixWithTieredPricingPrice value => + newPlanScalableMatrixWithTieredPricing(value), + NewPlanCumulativeGroupedBulkPrice value => newPlanCumulativeGroupedBulk(value), + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewPlanMinimumCompositePrice value => newPlanMinimumComposite(value), + global::Orb.Models.Beta.ExternalPlanID.Percent value => percent(value), + global::Orb.Models.Beta.ExternalPlanID.EventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Price"), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanUnitPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanMatrixPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanGroupedTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanUnitWithPercentPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + global::Orb.Models.Beta.ExternalPlanID.TieredWithProration value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanUnitWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanGroupedAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanBulkWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + NewPlanMinimumCompositePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + global::Orb.Models.Beta.ExternalPlanID.Percent value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.Price( + global::Orb.Models.Beta.ExternalPlanID.EventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + this.Switch( + (newPlanUnit) => newPlanUnit.Validate(), + (newPlanTiered) => newPlanTiered.Validate(), + (newPlanBulk) => newPlanBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newPlanPackage) => newPlanPackage.Validate(), + (newPlanMatrix) => newPlanMatrix.Validate(), + (newPlanThresholdTotalAmount) => newPlanThresholdTotalAmount.Validate(), + (newPlanTieredPackage) => newPlanTieredPackage.Validate(), + (newPlanTieredWithMinimum) => newPlanTieredWithMinimum.Validate(), + (newPlanGroupedTiered) => newPlanGroupedTiered.Validate(), + (newPlanTieredPackageWithMinimum) => newPlanTieredPackageWithMinimum.Validate(), + (newPlanPackageWithAllocation) => newPlanPackageWithAllocation.Validate(), + (newPlanUnitWithPercent) => newPlanUnitWithPercent.Validate(), + (newPlanMatrixWithAllocation) => newPlanMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newPlanUnitWithProration) => newPlanUnitWithProration.Validate(), + (newPlanGroupedAllocation) => newPlanGroupedAllocation.Validate(), + (newPlanBulkWithProration) => newPlanBulkWithProration.Validate(), + (newPlanGroupedWithProratedMinimum) => newPlanGroupedWithProratedMinimum.Validate(), + (newPlanGroupedWithMeteredMinimum) => newPlanGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newPlanMatrixWithDisplayName) => newPlanMatrixWithDisplayName.Validate(), + (newPlanGroupedTieredPackage) => newPlanGroupedTieredPackage.Validate(), + (newPlanMaxGroupTieredPackage) => newPlanMaxGroupTieredPackage.Validate(), + (newPlanScalableMatrixWithUnitPricing) => + newPlanScalableMatrixWithUnitPricing.Validate(), + (newPlanScalableMatrixWithTieredPricing) => + newPlanScalableMatrixWithTieredPricing.Validate(), + (newPlanCumulativeGroupedBulk) => newPlanCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newPlanMinimumComposite) => newPlanMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Beta.ExternalPlanID.Price? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceConverter : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.Price? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.Price(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.Price? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters, + global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersFromRaw + >) +)] +public sealed record class BulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public BulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public BulkWithFilters(global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters bulkWithFilters) + : base(bulkWithFilters) { } + + public BulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.BulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfig, + global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfigFromRaw + >) +)] +public sealed record class BulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithFiltersConfig() { } + + public BulkWithFiltersConfig( + global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfig bulkWithFiltersConfig + ) + : base(bulkWithFiltersConfig) { } + + public BulkWithFiltersConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.BulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.Filter, + global::Orb.Models.Beta.ExternalPlanID.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public Filter() { } + + public Filter(global::Orb.Models.Beta.ExternalPlanID.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.Filter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.Tier, + global::Orb.Models.Beta.ExternalPlanID.TierFromRaw + >) +)] +public sealed record class Tier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public Tier() { } + + public Tier(global::Orb.Models.Beta.ExternalPlanID.Tier tier) + : base(tier) { } + + public Tier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Tier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Tier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class TierFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.Tier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.CadenceConverter))] +public enum Cadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CadenceConverter : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.Cadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.ExternalPlanID.Cadence.Annual, + "semi_annual" => global::Orb.Models.Beta.ExternalPlanID.Cadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.ExternalPlanID.Cadence.Monthly, + "quarterly" => global::Orb.Models.Beta.ExternalPlanID.Cadence.Quarterly, + "one_time" => global::Orb.Models.Beta.ExternalPlanID.Cadence.OneTime, + "custom" => global::Orb.Models.Beta.ExternalPlanID.Cadence.Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.Cadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.Cadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.Cadence.Annual => "annual", + global::Orb.Models.Beta.ExternalPlanID.Cadence.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.Cadence.Monthly => "monthly", + global::Orb.Models.Beta.ExternalPlanID.Cadence.Quarterly => "quarterly", + global::Orb.Models.Beta.ExternalPlanID.Cadence.OneTime => "one_time", + global::Orb.Models.Beta.ExternalPlanID.Cadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfigConverter))] +public record class ConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ConversionRateConfig(SharedUnitConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(SharedTieredConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.TieredWithProration, + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationFromRaw + >) +)] +public sealed record class TieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public TieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public TieredWithProration( + global::Orb.Models.Beta.ExternalPlanID.TieredWithProration tieredWithProration + ) + : base(tieredWithProration) { } + + public TieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.TieredWithProration.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadenceConverter))] +public enum TieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class TieredWithProrationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .TieredWithProrationCadence + .SemiAnnual, + "monthly" => global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .TieredWithProrationCadence + .Quarterly, + "one_time" => global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.OneTime, + "custom" => global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Annual => + "annual", + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Monthly => + "monthly", + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Quarterly => + "quarterly", + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.OneTime => + "one_time", + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfig, + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigFromRaw + >) +)] +public sealed record class TieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredWithProrationConfig() { } + + public TieredWithProrationConfig( + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfig tieredWithProrationConfig + ) + : base(tieredWithProrationConfig) { } + + public TieredWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigTier, + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class TieredWithProrationConfigTier : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithProrationConfigTier() { } + + public TieredWithProrationConfigTier( + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigTier tieredWithProrationConfigTier + ) + : base(tieredWithProrationConfigTier) { } + + public TieredWithProrationConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfigConverter) +)] +public record class TieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.TieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds, + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public GroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public GroupedWithMinMaxThresholds( + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds groupedWithMinMaxThresholds + ) + : base(groupedWithMinMaxThresholds) { } + + public GroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholds.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadenceConverter) +)] +public enum GroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class GroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence.Annual => + "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .SemiAnnual => "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence.Monthly => + "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .GroupedWithMinMaxThresholdsCadence + .Quarterly => "quarterly", + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence.OneTime => + "one_time", + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfig, + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsConfig : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public GroupedWithMinMaxThresholdsConfig() { } + + public GroupedWithMinMaxThresholdsConfig( + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfig groupedWithMinMaxThresholdsConfig + ) + : base(groupedWithMinMaxThresholdsConfig) { } + + public GroupedWithMinMaxThresholdsConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class GroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.GroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation, + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public CumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public CumulativeGroupedAllocation( + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation cumulativeGroupedAllocation + ) + : base(cumulativeGroupedAllocation) { } + + public CumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocation.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadenceConverter) +)] +public enum CumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence.Annual => + "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .SemiAnnual => "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence.Monthly => + "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .CumulativeGroupedAllocationCadence + .Quarterly => "quarterly", + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence.OneTime => + "one_time", + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfig, + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationConfig : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public CumulativeGroupedAllocationConfig() { } + + public CumulativeGroupedAllocationConfig( + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfig cumulativeGroupedAllocationConfig + ) + : base(cumulativeGroupedAllocationConfig) { } + + public CumulativeGroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class CumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.CumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.Percent, + global::Orb.Models.Beta.ExternalPlanID.PercentFromRaw + >) +)] +public sealed record class Percent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.PercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public Percent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public Percent(global::Orb.Models.Beta.ExternalPlanID.Percent percent) + : base(percent) { } + + public Percent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.Percent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.PercentCadenceConverter))] +public enum PercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PercentCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.PercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.ExternalPlanID.PercentCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.ExternalPlanID.PercentCadence.OneTime, + "custom" => global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.PercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.PercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Annual => "annual", + global::Orb.Models.Beta.ExternalPlanID.PercentCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Monthly => "monthly", + global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.ExternalPlanID.PercentCadence.OneTime => "one_time", + global::Orb.Models.Beta.ExternalPlanID.PercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.PercentConfig, + global::Orb.Models.Beta.ExternalPlanID.PercentConfigFromRaw + >) +)] +public sealed record class PercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PercentConfig() { } + + public PercentConfig(global::Orb.Models.Beta.ExternalPlanID.PercentConfig percentConfig) + : base(percentConfig) { } + + public PercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PercentConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.PercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfigConverter))] +public record class PercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PercentConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.PercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.EventOutput, + global::Orb.Models.Beta.ExternalPlanID.EventOutputFromRaw + >) +)] +public sealed record class EventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.EventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public EventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public EventOutput(global::Orb.Models.Beta.ExternalPlanID.EventOutput eventOutput) + : base(eventOutput) { } + + public EventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.EventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.EventOutputCadenceConverter))] +public enum EventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class EventOutputCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Annual, + "semi_annual" => global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.SemiAnnual, + "monthly" => global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Monthly, + "quarterly" => global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Quarterly, + "one_time" => global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.OneTime, + "custom" => global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Annual => "annual", + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Monthly => "monthly", + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Quarterly => "quarterly", + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.OneTime => "one_time", + global::Orb.Models.Beta.ExternalPlanID.EventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.EventOutputConfig, + global::Orb.Models.Beta.ExternalPlanID.EventOutputConfigFromRaw + >) +)] +public sealed record class EventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public EventOutputConfig() { } + + public EventOutputConfig( + global::Orb.Models.Beta.ExternalPlanID.EventOutputConfig eventOutputConfig + ) + : base(eventOutputConfig) { } + + public EventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class EventOutputConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.EventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfigConverter) +)] +public record class EventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EventOutputConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.EventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.RemoveAdjustment, + global::Orb.Models.Beta.ExternalPlanID.RemoveAdjustmentFromRaw + >) +)] +public sealed record class RemoveAdjustment : JsonModel +{ + /// + /// The id of the adjustment to remove from on the plan. + /// + public required string AdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment_id"); } + init { JsonModel.Set(this._rawData, "adjustment_id", value); } + } + + /// + /// The phase to remove this adjustment from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + _ = this.AdjustmentID; + _ = this.PlanPhaseOrder; + } + + public RemoveAdjustment() { } + + public RemoveAdjustment( + global::Orb.Models.Beta.ExternalPlanID.RemoveAdjustment removeAdjustment + ) + : base(removeAdjustment) { } + + public RemoveAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + RemoveAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.RemoveAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public RemoveAdjustment(string adjustmentID) + : this() + { + this.AdjustmentID = adjustmentID; + } +} + +class RemoveAdjustmentFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.RemoveAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.RemoveAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.RemovePrice, + global::Orb.Models.Beta.ExternalPlanID.RemovePriceFromRaw + >) +)] +public sealed record class RemovePrice : JsonModel +{ + /// + /// The id of the price to remove from the plan. + /// + public required string PriceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + /// The phase to remove this price from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + _ = this.PriceID; + _ = this.PlanPhaseOrder; + } + + public RemovePrice() { } + + public RemovePrice(global::Orb.Models.Beta.ExternalPlanID.RemovePrice removePrice) + : base(removePrice) { } + + public RemovePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + RemovePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.RemovePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public RemovePrice(string priceID) + : this() + { + this.PriceID = priceID; + } +} + +class RemovePriceFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.RemovePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.RemovePrice.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustment, + global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentFromRaw + >) +)] +public sealed record class ReplaceAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the plan. + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment Adjustment + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" + ); + } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The id of the adjustment on the plan to replace in the plan. + /// + public required string ReplacesAdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } + } + + /// + /// The phase to replace this adjustment from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.ReplacesAdjustmentID; + _ = this.PlanPhaseOrder; + } + + public ReplaceAdjustment() { } + + public ReplaceAdjustment( + global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustment replaceAdjustment + ) + : base(replaceAdjustment) { } + + public ReplaceAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplaceAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplaceAdjustmentFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the plan. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustmentConverter))] +public record class ReplaceAdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public ReplaceAdjustmentAdjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment( + NewUsageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment( + NewAmountDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment( + NewMinimum value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment( + NewMaximum value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplaceAdjustmentAdjustmentConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplaceAdjustmentAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePrice, + global::Orb.Models.Beta.ExternalPlanID.ReplacePriceFromRaw + >) +)] +public sealed record class ReplacePrice : JsonModel +{ + /// + /// The id of the price on the plan to replace in the plan. + /// + public required string ReplacesPriceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// The allocation price to add to the plan. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// The phase to replace this price from. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New plan price request body params. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice? Price + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "price" + ); + } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + public override void Validate() + { + _ = this.ReplacesPriceID; + this.AllocationPrice?.Validate(); + _ = this.PlanPhaseOrder; + this.Price?.Validate(); + } + + public ReplacePrice() { } + + public ReplacePrice(global::Orb.Models.Beta.ExternalPlanID.ReplacePrice replacePrice) + : base(replacePrice) { } + + public ReplacePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePrice(string replacesPriceID) + : this() + { + this.ReplacesPriceID = replacesPriceID; + } +} + +class ReplacePriceFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.ReplacePrice.FromRawUnchecked(rawData); +} + +/// +/// New plan price request body params. +/// +[JsonConverter(typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceConverter))] +public record class ReplacePricePrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newPlanUnit: (x) => x.ItemID, + newPlanTiered: (x) => x.ItemID, + newPlanBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newPlanPackage: (x) => x.ItemID, + newPlanMatrix: (x) => x.ItemID, + newPlanThresholdTotalAmount: (x) => x.ItemID, + newPlanTieredPackage: (x) => x.ItemID, + newPlanTieredWithMinimum: (x) => x.ItemID, + newPlanGroupedTiered: (x) => x.ItemID, + newPlanTieredPackageWithMinimum: (x) => x.ItemID, + newPlanPackageWithAllocation: (x) => x.ItemID, + newPlanUnitWithPercent: (x) => x.ItemID, + newPlanMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newPlanUnitWithProration: (x) => x.ItemID, + newPlanGroupedAllocation: (x) => x.ItemID, + newPlanBulkWithProration: (x) => x.ItemID, + newPlanGroupedWithProratedMinimum: (x) => x.ItemID, + newPlanGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newPlanMatrixWithDisplayName: (x) => x.ItemID, + newPlanGroupedTieredPackage: (x) => x.ItemID, + newPlanMaxGroupTieredPackage: (x) => x.ItemID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ItemID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ItemID, + newPlanCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newPlanMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newPlanUnit: (x) => x.Name, + newPlanTiered: (x) => x.Name, + newPlanBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newPlanPackage: (x) => x.Name, + newPlanMatrix: (x) => x.Name, + newPlanThresholdTotalAmount: (x) => x.Name, + newPlanTieredPackage: (x) => x.Name, + newPlanTieredWithMinimum: (x) => x.Name, + newPlanGroupedTiered: (x) => x.Name, + newPlanTieredPackageWithMinimum: (x) => x.Name, + newPlanPackageWithAllocation: (x) => x.Name, + newPlanUnitWithPercent: (x) => x.Name, + newPlanMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newPlanUnitWithProration: (x) => x.Name, + newPlanGroupedAllocation: (x) => x.Name, + newPlanBulkWithProration: (x) => x.Name, + newPlanGroupedWithProratedMinimum: (x) => x.Name, + newPlanGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newPlanMatrixWithDisplayName: (x) => x.Name, + newPlanGroupedTieredPackage: (x) => x.Name, + newPlanMaxGroupTieredPackage: (x) => x.Name, + newPlanScalableMatrixWithUnitPricing: (x) => x.Name, + newPlanScalableMatrixWithTieredPricing: (x) => x.Name, + newPlanCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newPlanMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newPlanUnit: (x) => x.BillableMetricID, + newPlanTiered: (x) => x.BillableMetricID, + newPlanBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newPlanPackage: (x) => x.BillableMetricID, + newPlanMatrix: (x) => x.BillableMetricID, + newPlanThresholdTotalAmount: (x) => x.BillableMetricID, + newPlanTieredPackage: (x) => x.BillableMetricID, + newPlanTieredWithMinimum: (x) => x.BillableMetricID, + newPlanGroupedTiered: (x) => x.BillableMetricID, + newPlanTieredPackageWithMinimum: (x) => x.BillableMetricID, + newPlanPackageWithAllocation: (x) => x.BillableMetricID, + newPlanUnitWithPercent: (x) => x.BillableMetricID, + newPlanMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newPlanUnitWithProration: (x) => x.BillableMetricID, + newPlanGroupedAllocation: (x) => x.BillableMetricID, + newPlanBulkWithProration: (x) => x.BillableMetricID, + newPlanGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newPlanGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newPlanMatrixWithDisplayName: (x) => x.BillableMetricID, + newPlanGroupedTieredPackage: (x) => x.BillableMetricID, + newPlanMaxGroupTieredPackage: (x) => x.BillableMetricID, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newPlanCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newPlanMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newPlanUnit: (x) => x.BilledInAdvance, + newPlanTiered: (x) => x.BilledInAdvance, + newPlanBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newPlanPackage: (x) => x.BilledInAdvance, + newPlanMatrix: (x) => x.BilledInAdvance, + newPlanThresholdTotalAmount: (x) => x.BilledInAdvance, + newPlanTieredPackage: (x) => x.BilledInAdvance, + newPlanTieredWithMinimum: (x) => x.BilledInAdvance, + newPlanGroupedTiered: (x) => x.BilledInAdvance, + newPlanTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newPlanPackageWithAllocation: (x) => x.BilledInAdvance, + newPlanUnitWithPercent: (x) => x.BilledInAdvance, + newPlanMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newPlanUnitWithProration: (x) => x.BilledInAdvance, + newPlanGroupedAllocation: (x) => x.BilledInAdvance, + newPlanBulkWithProration: (x) => x.BilledInAdvance, + newPlanGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newPlanGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newPlanMatrixWithDisplayName: (x) => x.BilledInAdvance, + newPlanGroupedTieredPackage: (x) => x.BilledInAdvance, + newPlanMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newPlanCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newPlanMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.BillingCycleConfiguration, + newPlanTiered: (x) => x.BillingCycleConfiguration, + newPlanBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newPlanPackage: (x) => x.BillingCycleConfiguration, + newPlanMatrix: (x) => x.BillingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newPlanTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedTiered: (x) => x.BillingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newPlanUnitWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanBulkWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newPlanUnit: (x) => x.ConversionRate, + newPlanTiered: (x) => x.ConversionRate, + newPlanBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newPlanPackage: (x) => x.ConversionRate, + newPlanMatrix: (x) => x.ConversionRate, + newPlanThresholdTotalAmount: (x) => x.ConversionRate, + newPlanTieredPackage: (x) => x.ConversionRate, + newPlanTieredWithMinimum: (x) => x.ConversionRate, + newPlanGroupedTiered: (x) => x.ConversionRate, + newPlanTieredPackageWithMinimum: (x) => x.ConversionRate, + newPlanPackageWithAllocation: (x) => x.ConversionRate, + newPlanUnitWithPercent: (x) => x.ConversionRate, + newPlanMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newPlanUnitWithProration: (x) => x.ConversionRate, + newPlanGroupedAllocation: (x) => x.ConversionRate, + newPlanBulkWithProration: (x) => x.ConversionRate, + newPlanGroupedWithProratedMinimum: (x) => x.ConversionRate, + newPlanGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newPlanMatrixWithDisplayName: (x) => x.ConversionRate, + newPlanGroupedTieredPackage: (x) => x.ConversionRate, + newPlanMaxGroupTieredPackage: (x) => x.ConversionRate, + newPlanScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newPlanScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newPlanCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newPlanMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newPlanUnit: (x) => x.Currency, + newPlanTiered: (x) => x.Currency, + newPlanBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newPlanPackage: (x) => x.Currency, + newPlanMatrix: (x) => x.Currency, + newPlanThresholdTotalAmount: (x) => x.Currency, + newPlanTieredPackage: (x) => x.Currency, + newPlanTieredWithMinimum: (x) => x.Currency, + newPlanGroupedTiered: (x) => x.Currency, + newPlanTieredPackageWithMinimum: (x) => x.Currency, + newPlanPackageWithAllocation: (x) => x.Currency, + newPlanUnitWithPercent: (x) => x.Currency, + newPlanMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newPlanUnitWithProration: (x) => x.Currency, + newPlanGroupedAllocation: (x) => x.Currency, + newPlanBulkWithProration: (x) => x.Currency, + newPlanGroupedWithProratedMinimum: (x) => x.Currency, + newPlanGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newPlanMatrixWithDisplayName: (x) => x.Currency, + newPlanGroupedTieredPackage: (x) => x.Currency, + newPlanMaxGroupTieredPackage: (x) => x.Currency, + newPlanScalableMatrixWithUnitPricing: (x) => x.Currency, + newPlanScalableMatrixWithTieredPricing: (x) => x.Currency, + newPlanCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newPlanMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.DimensionalPriceConfiguration, + newPlanTiered: (x) => x.DimensionalPriceConfiguration, + newPlanBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newPlanPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMatrix: (x) => x.DimensionalPriceConfiguration, + newPlanThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newPlanUnit: (x) => x.ExternalPriceID, + newPlanTiered: (x) => x.ExternalPriceID, + newPlanBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newPlanPackage: (x) => x.ExternalPriceID, + newPlanMatrix: (x) => x.ExternalPriceID, + newPlanThresholdTotalAmount: (x) => x.ExternalPriceID, + newPlanTieredPackage: (x) => x.ExternalPriceID, + newPlanTieredWithMinimum: (x) => x.ExternalPriceID, + newPlanGroupedTiered: (x) => x.ExternalPriceID, + newPlanTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newPlanPackageWithAllocation: (x) => x.ExternalPriceID, + newPlanUnitWithPercent: (x) => x.ExternalPriceID, + newPlanMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newPlanUnitWithProration: (x) => x.ExternalPriceID, + newPlanGroupedAllocation: (x) => x.ExternalPriceID, + newPlanBulkWithProration: (x) => x.ExternalPriceID, + newPlanGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newPlanMatrixWithDisplayName: (x) => x.ExternalPriceID, + newPlanGroupedTieredPackage: (x) => x.ExternalPriceID, + newPlanMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newPlanCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newPlanMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newPlanUnit: (x) => x.FixedPriceQuantity, + newPlanTiered: (x) => x.FixedPriceQuantity, + newPlanBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newPlanPackage: (x) => x.FixedPriceQuantity, + newPlanMatrix: (x) => x.FixedPriceQuantity, + newPlanThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newPlanTieredPackage: (x) => x.FixedPriceQuantity, + newPlanTieredWithMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedTiered: (x) => x.FixedPriceQuantity, + newPlanTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newPlanPackageWithAllocation: (x) => x.FixedPriceQuantity, + newPlanUnitWithPercent: (x) => x.FixedPriceQuantity, + newPlanMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newPlanUnitWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanBulkWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newPlanMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newPlanGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newPlanMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newPlanCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newPlanUnit: (x) => x.InvoiceGroupingKey, + newPlanTiered: (x) => x.InvoiceGroupingKey, + newPlanBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newPlanPackage: (x) => x.InvoiceGroupingKey, + newPlanMatrix: (x) => x.InvoiceGroupingKey, + newPlanThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newPlanTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedTiered: (x) => x.InvoiceGroupingKey, + newPlanTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newPlanUnitWithPercent: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newPlanUnitWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanBulkWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newPlanGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newPlanCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.InvoicingCycleConfiguration, + newPlanTiered: (x) => x.InvoicingCycleConfiguration, + newPlanBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newPlanPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMatrix: (x) => x.InvoicingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newPlanUnit: (x) => x.ReferenceID, + newPlanTiered: (x) => x.ReferenceID, + newPlanBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newPlanPackage: (x) => x.ReferenceID, + newPlanMatrix: (x) => x.ReferenceID, + newPlanThresholdTotalAmount: (x) => x.ReferenceID, + newPlanTieredPackage: (x) => x.ReferenceID, + newPlanTieredWithMinimum: (x) => x.ReferenceID, + newPlanGroupedTiered: (x) => x.ReferenceID, + newPlanTieredPackageWithMinimum: (x) => x.ReferenceID, + newPlanPackageWithAllocation: (x) => x.ReferenceID, + newPlanUnitWithPercent: (x) => x.ReferenceID, + newPlanMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newPlanUnitWithProration: (x) => x.ReferenceID, + newPlanGroupedAllocation: (x) => x.ReferenceID, + newPlanBulkWithProration: (x) => x.ReferenceID, + newPlanGroupedWithProratedMinimum: (x) => x.ReferenceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newPlanMatrixWithDisplayName: (x) => x.ReferenceID, + newPlanGroupedTieredPackage: (x) => x.ReferenceID, + newPlanMaxGroupTieredPackage: (x) => x.ReferenceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newPlanCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newPlanMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public ReplacePricePrice(NewPlanUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanTieredPackageWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanGroupedWithProratedMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanGroupedWithMeteredMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewPlanScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewPlanMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnit(out var value)) { + /// // `value` is of type `NewPlanUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnit([NotNullWhen(true)] out NewPlanUnitPrice? value) + { + value = this.Value as NewPlanUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTiered(out var value)) { + /// // `value` is of type `NewPlanTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTiered([NotNullWhen(true)] out NewPlanTieredPrice? value) + { + value = this.Value as NewPlanTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulk(out var value)) { + /// // `value` is of type `NewPlanBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulk([NotNullWhen(true)] out NewPlanBulkPrice? value) + { + value = this.Value as NewPlanBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters? value + ) + { + value = + this.Value as global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackage(out var value)) { + /// // `value` is of type `NewPlanPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackage([NotNullWhen(true)] out NewPlanPackagePrice? value) + { + value = this.Value as NewPlanPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrix(out var value)) { + /// // `value` is of type `NewPlanMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrix([NotNullWhen(true)] out NewPlanMatrixPrice? value) + { + value = this.Value as NewPlanMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewPlanThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanThresholdTotalAmount( + [NotNullWhen(true)] out NewPlanThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewPlanThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackage(out var value)) { + /// // `value` is of type `NewPlanTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackage( + [NotNullWhen(true)] out NewPlanTieredPackagePrice? value + ) + { + value = this.Value as NewPlanTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredWithMinimum( + [NotNullWhen(true)] out NewPlanTieredWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTiered(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTiered( + [NotNullWhen(true)] out NewPlanGroupedTieredPrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackageWithMinimum( + [NotNullWhen(true)] out NewPlanTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackageWithAllocation(out var value)) { + /// // `value` is of type `NewPlanPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackageWithAllocation( + [NotNullWhen(true)] out NewPlanPackageWithAllocationPrice? value + ) + { + value = this.Value as NewPlanPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithPercent(out var value)) { + /// // `value` is of type `NewPlanUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithPercent( + [NotNullWhen(true)] out NewPlanUnitWithPercentPrice? value + ) + { + value = this.Value as NewPlanUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewPlanMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithAllocation( + [NotNullWhen(true)] out NewPlanMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewPlanMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration? value + ) + { + value = + this.Value + as global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithProration(out var value)) { + /// // `value` is of type `NewPlanUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithProration( + [NotNullWhen(true)] out NewPlanUnitWithProrationPrice? value + ) + { + value = this.Value as NewPlanUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedAllocation(out var value)) { + /// // `value` is of type `NewPlanGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedAllocation( + [NotNullWhen(true)] out NewPlanGroupedAllocationPrice? value + ) + { + value = this.Value as NewPlanGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulkWithProration(out var value)) { + /// // `value` is of type `NewPlanBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulkWithProration( + [NotNullWhen(true)] out NewPlanBulkWithProrationPrice? value + ) + { + value = this.Value as NewPlanBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds? value + ) + { + value = + this.Value + as global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewPlanMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithDisplayName( + [NotNullWhen(true)] out NewPlanMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewPlanMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTieredPackage( + [NotNullWhen(true)] out NewPlanGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewPlanMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMaxGroupTieredPackage( + [NotNullWhen(true)] out NewPlanMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewPlanMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewPlanCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanCumulativeGroupedBulk( + [NotNullWhen(true)] out NewPlanCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewPlanCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation? value + ) + { + value = + this.Value + as global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMinimumComposite(out var value)) { + /// // `value` is of type `NewPlanMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMinimumComposite( + [NotNullWhen(true)] out NewPlanMinimumCompositePrice? value + ) + { + value = this.Value as NewPlanMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] + out global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput? value + ) + { + value = this.Value as global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPlanUnit, + System::Action newPlanTiered, + System::Action newPlanBulk, + System::Action bulkWithFilters, + System::Action newPlanPackage, + System::Action newPlanMatrix, + System::Action newPlanThresholdTotalAmount, + System::Action newPlanTieredPackage, + System::Action newPlanTieredWithMinimum, + System::Action newPlanGroupedTiered, + System::Action newPlanTieredPackageWithMinimum, + System::Action newPlanPackageWithAllocation, + System::Action newPlanUnitWithPercent, + System::Action newPlanMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newPlanUnitWithProration, + System::Action newPlanGroupedAllocation, + System::Action newPlanBulkWithProration, + System::Action newPlanGroupedWithProratedMinimum, + System::Action newPlanGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newPlanMatrixWithDisplayName, + System::Action newPlanGroupedTieredPackage, + System::Action newPlanMaxGroupTieredPackage, + System::Action newPlanScalableMatrixWithUnitPricing, + System::Action newPlanScalableMatrixWithTieredPricing, + System::Action newPlanCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newPlanMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewPlanUnitPrice value: + newPlanUnit(value); + break; + case NewPlanTieredPrice value: + newPlanTiered(value); + break; + case NewPlanBulkPrice value: + newPlanBulk(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewPlanPackagePrice value: + newPlanPackage(value); + break; + case NewPlanMatrixPrice value: + newPlanMatrix(value); + break; + case NewPlanThresholdTotalAmountPrice value: + newPlanThresholdTotalAmount(value); + break; + case NewPlanTieredPackagePrice value: + newPlanTieredPackage(value); + break; + case NewPlanTieredWithMinimumPrice value: + newPlanTieredWithMinimum(value); + break; + case NewPlanGroupedTieredPrice value: + newPlanGroupedTiered(value); + break; + case NewPlanTieredPackageWithMinimumPrice value: + newPlanTieredPackageWithMinimum(value); + break; + case NewPlanPackageWithAllocationPrice value: + newPlanPackageWithAllocation(value); + break; + case NewPlanUnitWithPercentPrice value: + newPlanUnitWithPercent(value); + break; + case NewPlanMatrixWithAllocationPrice value: + newPlanMatrixWithAllocation(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration value: + tieredWithProration(value); + break; + case NewPlanUnitWithProrationPrice value: + newPlanUnitWithProration(value); + break; + case NewPlanGroupedAllocationPrice value: + newPlanGroupedAllocation(value); + break; + case NewPlanBulkWithProrationPrice value: + newPlanBulkWithProration(value); + break; + case NewPlanGroupedWithProratedMinimumPrice value: + newPlanGroupedWithProratedMinimum(value); + break; + case NewPlanGroupedWithMeteredMinimumPrice value: + newPlanGroupedWithMeteredMinimum(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewPlanMatrixWithDisplayNamePrice value: + newPlanMatrixWithDisplayName(value); + break; + case NewPlanGroupedTieredPackagePrice value: + newPlanGroupedTieredPackage(value); + break; + case NewPlanMaxGroupTieredPackagePrice value: + newPlanMaxGroupTieredPackage(value); + break; + case NewPlanScalableMatrixWithUnitPricingPrice value: + newPlanScalableMatrixWithUnitPricing(value); + break; + case NewPlanScalableMatrixWithTieredPricingPrice value: + newPlanScalableMatrixWithTieredPricing(value); + break; + case NewPlanCumulativeGroupedBulkPrice value: + newPlanCumulativeGroupedBulk(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewPlanMinimumCompositePrice value: + newPlanMinimumComposite(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent value: + percent(value); + break; + case global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent value) => {...}, + /// (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPlanUnit, + System::Func newPlanTiered, + System::Func newPlanBulk, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters, + T + > bulkWithFilters, + System::Func newPlanPackage, + System::Func newPlanMatrix, + System::Func newPlanThresholdTotalAmount, + System::Func newPlanTieredPackage, + System::Func newPlanTieredWithMinimum, + System::Func newPlanGroupedTiered, + System::Func newPlanTieredPackageWithMinimum, + System::Func newPlanPackageWithAllocation, + System::Func newPlanUnitWithPercent, + System::Func newPlanMatrixWithAllocation, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration, + T + > tieredWithProration, + System::Func newPlanUnitWithProration, + System::Func newPlanGroupedAllocation, + System::Func newPlanBulkWithProration, + System::Func newPlanGroupedWithProratedMinimum, + System::Func newPlanGroupedWithMeteredMinimum, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func newPlanMatrixWithDisplayName, + System::Func newPlanGroupedTieredPackage, + System::Func newPlanMaxGroupTieredPackage, + System::Func< + NewPlanScalableMatrixWithUnitPricingPrice, + T + > newPlanScalableMatrixWithUnitPricing, + System::Func< + NewPlanScalableMatrixWithTieredPricingPrice, + T + > newPlanScalableMatrixWithTieredPricing, + System::Func newPlanCumulativeGroupedBulk, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newPlanMinimumComposite, + System::Func percent, + System::Func< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput, + T + > eventOutput + ) + { + return this.Value switch + { + NewPlanUnitPrice value => newPlanUnit(value), + NewPlanTieredPrice value => newPlanTiered(value), + NewPlanBulkPrice value => newPlanBulk(value), + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters value => + bulkWithFilters(value), + NewPlanPackagePrice value => newPlanPackage(value), + NewPlanMatrixPrice value => newPlanMatrix(value), + NewPlanThresholdTotalAmountPrice value => newPlanThresholdTotalAmount(value), + NewPlanTieredPackagePrice value => newPlanTieredPackage(value), + NewPlanTieredWithMinimumPrice value => newPlanTieredWithMinimum(value), + NewPlanGroupedTieredPrice value => newPlanGroupedTiered(value), + NewPlanTieredPackageWithMinimumPrice value => newPlanTieredPackageWithMinimum(value), + NewPlanPackageWithAllocationPrice value => newPlanPackageWithAllocation(value), + NewPlanUnitWithPercentPrice value => newPlanUnitWithPercent(value), + NewPlanMatrixWithAllocationPrice value => newPlanMatrixWithAllocation(value), + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration value => + tieredWithProration(value), + NewPlanUnitWithProrationPrice value => newPlanUnitWithProration(value), + NewPlanGroupedAllocationPrice value => newPlanGroupedAllocation(value), + NewPlanBulkWithProrationPrice value => newPlanBulkWithProration(value), + NewPlanGroupedWithProratedMinimumPrice value => newPlanGroupedWithProratedMinimum( + value + ), + NewPlanGroupedWithMeteredMinimumPrice value => newPlanGroupedWithMeteredMinimum(value), + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewPlanMatrixWithDisplayNamePrice value => newPlanMatrixWithDisplayName(value), + NewPlanGroupedTieredPackagePrice value => newPlanGroupedTieredPackage(value), + NewPlanMaxGroupTieredPackagePrice value => newPlanMaxGroupTieredPackage(value), + NewPlanScalableMatrixWithUnitPricingPrice value => newPlanScalableMatrixWithUnitPricing( + value + ), + NewPlanScalableMatrixWithTieredPricingPrice value => + newPlanScalableMatrixWithTieredPricing(value), + NewPlanCumulativeGroupedBulkPrice value => newPlanCumulativeGroupedBulk(value), + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewPlanMinimumCompositePrice value => newPlanMinimumComposite(value), + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent value => percent(value), + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput value => + eventOutput(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanUnitPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanMatrixPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanGroupedTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanUnitWithPercentPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanUnitWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanGroupedAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanBulkWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + NewPlanMinimumCompositePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ); + } + this.Switch( + (newPlanUnit) => newPlanUnit.Validate(), + (newPlanTiered) => newPlanTiered.Validate(), + (newPlanBulk) => newPlanBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newPlanPackage) => newPlanPackage.Validate(), + (newPlanMatrix) => newPlanMatrix.Validate(), + (newPlanThresholdTotalAmount) => newPlanThresholdTotalAmount.Validate(), + (newPlanTieredPackage) => newPlanTieredPackage.Validate(), + (newPlanTieredWithMinimum) => newPlanTieredWithMinimum.Validate(), + (newPlanGroupedTiered) => newPlanGroupedTiered.Validate(), + (newPlanTieredPackageWithMinimum) => newPlanTieredPackageWithMinimum.Validate(), + (newPlanPackageWithAllocation) => newPlanPackageWithAllocation.Validate(), + (newPlanUnitWithPercent) => newPlanUnitWithPercent.Validate(), + (newPlanMatrixWithAllocation) => newPlanMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newPlanUnitWithProration) => newPlanUnitWithProration.Validate(), + (newPlanGroupedAllocation) => newPlanGroupedAllocation.Validate(), + (newPlanBulkWithProration) => newPlanBulkWithProration.Validate(), + (newPlanGroupedWithProratedMinimum) => newPlanGroupedWithProratedMinimum.Validate(), + (newPlanGroupedWithMeteredMinimum) => newPlanGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newPlanMatrixWithDisplayName) => newPlanMatrixWithDisplayName.Validate(), + (newPlanGroupedTieredPackage) => newPlanGroupedTieredPackage.Validate(), + (newPlanMaxGroupTieredPackage) => newPlanMaxGroupTieredPackage.Validate(), + (newPlanScalableMatrixWithUnitPricing) => + newPlanScalableMatrixWithUnitPricing.Validate(), + (newPlanScalableMatrixWithTieredPricing) => + newPlanScalableMatrixWithTieredPricing.Validate(), + (newPlanCumulativeGroupedBulk) => newPlanCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newPlanMinimumComposite) => newPlanMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public ReplacePricePriceBulkWithFilters( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters replacePricePriceBulkWithFilters + ) + : base(replacePricePriceBulkWithFilters) { } + + public ReplacePricePriceBulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFilters.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig replacePricePriceBulkWithFiltersBulkWithFiltersConfig + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfig) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter replacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier replacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfigTier) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersCadenceConverter) +)] +public enum ReplacePricePriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Annual => "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .SemiAnnual => "semi_annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Monthly => "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Quarterly => "quarterly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .OneTime => "one_time", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceBulkWithFiltersCadence + .Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfigConverter) +)] +public record class ReplacePricePriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceTieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public ReplacePricePriceTieredWithProration( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration replacePricePriceTieredWithProration + ) + : base(replacePricePriceTieredWithProration) { } + + public ReplacePricePriceTieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceTieredWithProrationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProration.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationCadenceConverter) +)] +public enum ReplacePricePriceTieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceTieredWithProrationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Custom, + _ => + (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Annual => "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .SemiAnnual => "semi_annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Monthly => "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Quarterly => "quarterly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .OneTime => "one_time", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceTieredWithProrationCadence + .Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfig, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProrationTieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig() { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfig replacePricePriceTieredWithProrationTieredWithProrationConfig + ) + : base(replacePricePriceTieredWithProrationTieredWithProrationConfig) { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class ReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier() { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier replacePricePriceTieredWithProrationTieredWithProrationConfigTier + ) + : base(replacePricePriceTieredWithProrationTieredWithProrationConfigTier) { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfigConverter) +)] +public record class ReplacePricePriceTieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceTieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceTieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class ReplacePricePriceGroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public ReplacePricePriceGroupedWithMinMaxThresholds( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds replacePricePriceGroupedWithMinMaxThresholds + ) + : base(replacePricePriceGroupedWithMinMaxThresholds) { } + + public ReplacePricePriceGroupedWithMinMaxThresholds( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceGroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholds.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter) +)] +public enum ReplacePricePriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Custom, + _ => + (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Annual => "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .SemiAnnual => "semi_annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Monthly => "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Quarterly => "quarterly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .OneTime => "one_time", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceGroupedWithMinMaxThresholdsCadence + .Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() { } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig replacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base(replacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig) { } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class ReplacePricePriceCumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public ReplacePricePriceCumulativeGroupedAllocation( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation replacePricePriceCumulativeGroupedAllocation + ) + : base(replacePricePriceCumulativeGroupedAllocation) { } + + public ReplacePricePriceCumulativeGroupedAllocation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceCumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocation.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCadenceConverter) +)] +public enum ReplacePricePriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Custom, + _ => + (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Annual => "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .SemiAnnual => "semi_annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Monthly => "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Quarterly => "quarterly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .OneTime => "one_time", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceCumulativeGroupedAllocationCadence + .Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() { } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig replacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base(replacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig) { } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentFromRaw + >) +)] +public sealed record class ReplacePricePricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public ReplacePricePricePercent( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent replacePricePricePercent + ) + : base(replacePricePricePercent) { } + + public ReplacePricePricePercent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePricePercent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePricePercentFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadenceConverter) +)] +public enum ReplacePricePricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePricePercentCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePricePercentCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePricePercentCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePricePercentCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePricePercentCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePricePercentCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePricePercentCadence + .Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence.Annual => + "annual", + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence.Monthly => + "monthly", + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence.Quarterly => + "quarterly", + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence.OneTime => + "one_time", + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfig, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfigFromRaw + >) +)] +public sealed record class ReplacePricePricePercentPercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public ReplacePricePricePercentPercentConfig() { } + + public ReplacePricePricePercentPercentConfig( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfig replacePricePricePercentPercentConfig + ) + : base(replacePricePricePercentPercentConfig) { } + + public ReplacePricePricePercentPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePricePercentPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class ReplacePricePricePercentPercentConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentPercentConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfigConverter) +)] +public record class ReplacePricePricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePricePercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePricePercentConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputFromRaw + >) +)] +public sealed record class ReplacePricePriceEventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public ReplacePricePriceEventOutput( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput replacePricePriceEventOutput + ) + : base(replacePricePriceEventOutput) { } + + public ReplacePricePriceEventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceEventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceEventOutputFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutput.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadenceConverter) +)] +public enum ReplacePricePriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceEventOutputCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .Annual, + "semi_annual" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .OneTime, + "custom" => global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .Custom, + _ => (global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence.Annual => + "annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .SemiAnnual => "semi_annual", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .Monthly => "monthly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .Quarterly => "quarterly", + global::Orb + .Models + .Beta + .ExternalPlanID + .ReplacePricePriceEventOutputCadence + .OneTime => "one_time", + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfig, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceEventOutputEventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public ReplacePricePriceEventOutputEventOutputConfig() { } + + public ReplacePricePriceEventOutputEventOutputConfig( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfig replacePricePriceEventOutputEventOutputConfig + ) + : base(replacePricePriceEventOutputEventOutputConfig) { } + + public ReplacePricePriceEventOutputEventOutputConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceEventOutputEventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceEventOutputEventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class ReplacePricePriceEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputEventOutputConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfigConverter) +)] +public record class ReplacePricePriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceEventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.ExternalPlanID.ReplacePricePriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustment.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustment.cs deleted file mode 100644 index 5a8195b8..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustment.cs +++ /dev/null @@ -1,73 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddAdjustmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the plan. - /// - public required AddAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this adjustment to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.PlanPhaseOrder; - } - - public AddAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustmentProperties/Adjustment.cs deleted file mode 100644 index bd9ab4ca..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the plan. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 388b85ee..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPrice.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPrice.cs deleted file mode 100644 index 1b794dab..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPrice.cs +++ /dev/null @@ -1,88 +0,0 @@ -using AddPriceProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddPriceProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddPrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The allocation price to add to the plan. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The phase to add this price to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The price to add to the plan - /// - public AddPriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.AllocationPrice?.Validate(); - _ = this.PlanPhaseOrder; - this.Price?.Validate(); - } - - public AddPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPriceProperties/Price.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPriceProperties/Price.cs deleted file mode 100644 index f1707164..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPriceProperties/Price.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddPriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddPriceProperties; - -/// -/// The price to add to the plan -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewPlanUnitPrice Create(Models::NewPlanUnitPrice value) => - new(value); - - public static PriceVariants::NewPlanPackagePrice Create(Models::NewPlanPackagePrice value) => - new(value); - - public static PriceVariants::NewPlanMatrixPrice Create(Models::NewPlanMatrixPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredPrice Create(Models::NewPlanTieredPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredBPSPrice Create( - Models::NewPlanTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewPlanBPSPrice Create(Models::NewPlanBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkBPSPrice Create(Models::NewPlanBulkBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkPrice Create(Models::NewPlanBulkPrice value) => - new(value); - - public static PriceVariants::NewPlanThresholdTotalAmountPrice Create( - Models::NewPlanThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackagePrice Create( - Models::NewPlanTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredWithMinimumPrice Create( - Models::NewPlanTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithPercentPrice Create( - Models::NewPlanUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewPlanPackageWithAllocationPrice Create( - Models::NewPlanPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanTierWithProrationPrice Create( - Models::NewPlanTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithProrationPrice Create( - Models::NewPlanUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedAllocationPrice Create( - Models::NewPlanGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithProratedMinimumPrice Create( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithMeteredMinimumPrice Create( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithDisplayNamePrice Create( - Models::NewPlanMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewPlanBulkWithProrationPrice Create( - Models::NewPlanBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPackagePrice Create( - Models::NewPlanGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanMaxGroupTieredPackagePrice Create( - Models::NewPlanMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithUnitPricingPrice Create( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithTieredPricingPrice Create( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanCumulativeGroupedBulkPrice Create( - Models::NewPlanCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackageWithMinimumPrice Create( - Models::NewPlanTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithAllocationPrice Create( - Models::NewPlanMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPrice Create( - Models::NewPlanGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPriceProperties/PriceVariants/All.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPriceProperties/PriceVariants/All.cs deleted file mode 100644 index 9911a0e2..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/AddPriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,634 +0,0 @@ -using AddPriceProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddPriceProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.AddPriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitPrice(Models::NewPlanUnitPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitPrice From(Models::NewPlanUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanPackagePrice(Models::NewPlanPackagePrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackagePrice From(Models::NewPlanPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanMatrixPrice(Models::NewPlanMatrixPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixPrice From(Models::NewPlanMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPrice(Models::NewPlanTieredPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPrice From(Models::NewPlanTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredBPSPrice(Models::NewPlanTieredBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredBPSPrice From(Models::NewPlanTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBPSPrice(Models::NewPlanBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBPSPrice From(Models::NewPlanBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkBPSPrice(Models::NewPlanBulkBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkBPSPrice From(Models::NewPlanBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkPrice(Models::NewPlanBulkPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkPrice From(Models::NewPlanBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanThresholdTotalAmountPrice, - Models::NewPlanThresholdTotalAmountPrice - >) -)] -public sealed record class NewPlanThresholdTotalAmountPrice( - Models::NewPlanThresholdTotalAmountPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanThresholdTotalAmountPrice From( - Models::NewPlanThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPackagePrice(Models::NewPlanTieredPackagePrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPackagePrice From(Models::NewPlanTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredWithMinimumPrice, - Models::NewPlanTieredWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredWithMinimumPrice( - Models::NewPlanTieredWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredWithMinimumPrice From(Models::NewPlanTieredWithMinimumPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitWithPercentPrice(Models::NewPlanUnitWithPercentPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithPercentPrice From(Models::NewPlanUnitWithPercentPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanPackageWithAllocationPrice, - Models::NewPlanPackageWithAllocationPrice - >) -)] -public sealed record class NewPlanPackageWithAllocationPrice( - Models::NewPlanPackageWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackageWithAllocationPrice From( - Models::NewPlanPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTierWithProrationPrice, - Models::NewPlanTierWithProrationPrice - >) -)] -public sealed record class NewPlanTierWithProrationPrice( - Models::NewPlanTierWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTierWithProrationPrice From(Models::NewPlanTierWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanUnitWithProrationPrice, - Models::NewPlanUnitWithProrationPrice - >) -)] -public sealed record class NewPlanUnitWithProrationPrice( - Models::NewPlanUnitWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithProrationPrice From(Models::NewPlanUnitWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedAllocationPrice, - Models::NewPlanGroupedAllocationPrice - >) -)] -public sealed record class NewPlanGroupedAllocationPrice( - Models::NewPlanGroupedAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedAllocationPrice From(Models::NewPlanGroupedAllocationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithProratedMinimumPrice( - Models::NewPlanGroupedWithProratedMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - > -{ - public static NewPlanGroupedWithProratedMinimumPrice From( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithMeteredMinimumPrice( - Models::NewPlanGroupedWithMeteredMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - > -{ - public static NewPlanGroupedWithMeteredMinimumPrice From( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithDisplayNamePrice, - Models::NewPlanMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewPlanMatrixWithDisplayNamePrice( - Models::NewPlanMatrixWithDisplayNamePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithDisplayNamePrice From( - Models::NewPlanMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanBulkWithProrationPrice, - Models::NewPlanBulkWithProrationPrice - >) -)] -public sealed record class NewPlanBulkWithProrationPrice( - Models::NewPlanBulkWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkWithProrationPrice From(Models::NewPlanBulkWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedTieredPackagePrice, - Models::NewPlanGroupedTieredPackagePrice - >) -)] -public sealed record class NewPlanGroupedTieredPackagePrice( - Models::NewPlanGroupedTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPackagePrice From( - Models::NewPlanGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMaxGroupTieredPackagePrice, - Models::NewPlanMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewPlanMaxGroupTieredPackagePrice( - Models::NewPlanMaxGroupTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMaxGroupTieredPackagePrice From( - Models::NewPlanMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithUnitPricingPrice( - Models::NewPlanScalableMatrixWithUnitPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - > -{ - public static NewPlanScalableMatrixWithUnitPricingPrice From( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithTieredPricingPrice( - Models::NewPlanScalableMatrixWithTieredPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - > -{ - public static NewPlanScalableMatrixWithTieredPricingPrice From( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanCumulativeGroupedBulkPrice, - Models::NewPlanCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewPlanCumulativeGroupedBulkPrice( - Models::NewPlanCumulativeGroupedBulkPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanCumulativeGroupedBulkPrice From( - Models::NewPlanCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredPackageWithMinimumPrice( - Models::NewPlanTieredPackageWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - > -{ - public static NewPlanTieredPackageWithMinimumPrice From( - Models::NewPlanTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithAllocationPrice, - Models::NewPlanMatrixWithAllocationPrice - >) -)] -public sealed record class NewPlanMatrixWithAllocationPrice( - Models::NewPlanMatrixWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithAllocationPrice From( - Models::NewPlanMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanGroupedTieredPrice(Models::NewPlanGroupedTieredPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPrice From(Models::NewPlanGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/RemoveAdjustment.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/RemoveAdjustment.cs deleted file mode 100644 index 87adf1e2..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/RemoveAdjustment.cs +++ /dev/null @@ -1,72 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemoveAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the adjustment to remove from on the plan. - /// - public required string AdjustmentID - { - get - { - if (!this.Properties.TryGetValue("adjustment_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_id"); - } - set { this.Properties["adjustment_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to remove this adjustment from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.AdjustmentID; - _ = this.PlanPhaseOrder; - } - - public RemoveAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemoveAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemoveAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/RemovePrice.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/RemovePrice.cs deleted file mode 100644 index 5fcedf63..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/RemovePrice.cs +++ /dev/null @@ -1,72 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemovePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price to remove from the plan. - /// - public required string PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to remove this price from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.PriceID; - _ = this.PlanPhaseOrder; - } - - public RemovePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemovePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemovePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustment.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustment.cs deleted file mode 100644 index 89e96ce8..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustment.cs +++ /dev/null @@ -1,104 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplaceAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the plan. - /// - public required ReplaceAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the adjustment on the plan to replace in the plan. - /// - public required string ReplacesAdjustmentID - { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_adjustment_id"); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The phase to replace this adjustment from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.ReplacesAdjustmentID; - _ = this.PlanPhaseOrder; - } - - public ReplaceAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplaceAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplaceAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs deleted file mode 100644 index 55daca0c..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the plan. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 38487a11..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePrice.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePrice.cs deleted file mode 100644 index 6a78cc65..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePrice.cs +++ /dev/null @@ -1,112 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplacePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price on the plan to replace in the plan. - /// - public required string ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_price_id"); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The allocation price to add to the plan. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The phase to replace this price from. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The price to add to the plan - /// - public ReplacePriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ReplacesPriceID; - this.AllocationPrice?.Validate(); - _ = this.PlanPhaseOrder; - this.Price?.Validate(); - } - - public ReplacePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplacePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplacePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePriceProperties/Price.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePriceProperties/Price.cs deleted file mode 100644 index cf41ed4e..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePriceProperties/Price.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplacePriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplacePriceProperties; - -/// -/// The price to add to the plan -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewPlanUnitPrice Create(Models::NewPlanUnitPrice value) => - new(value); - - public static PriceVariants::NewPlanPackagePrice Create(Models::NewPlanPackagePrice value) => - new(value); - - public static PriceVariants::NewPlanMatrixPrice Create(Models::NewPlanMatrixPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredPrice Create(Models::NewPlanTieredPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredBPSPrice Create( - Models::NewPlanTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewPlanBPSPrice Create(Models::NewPlanBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkBPSPrice Create(Models::NewPlanBulkBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkPrice Create(Models::NewPlanBulkPrice value) => - new(value); - - public static PriceVariants::NewPlanThresholdTotalAmountPrice Create( - Models::NewPlanThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackagePrice Create( - Models::NewPlanTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredWithMinimumPrice Create( - Models::NewPlanTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithPercentPrice Create( - Models::NewPlanUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewPlanPackageWithAllocationPrice Create( - Models::NewPlanPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanTierWithProrationPrice Create( - Models::NewPlanTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithProrationPrice Create( - Models::NewPlanUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedAllocationPrice Create( - Models::NewPlanGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithProratedMinimumPrice Create( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithMeteredMinimumPrice Create( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithDisplayNamePrice Create( - Models::NewPlanMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewPlanBulkWithProrationPrice Create( - Models::NewPlanBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPackagePrice Create( - Models::NewPlanGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanMaxGroupTieredPackagePrice Create( - Models::NewPlanMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithUnitPricingPrice Create( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithTieredPricingPrice Create( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanCumulativeGroupedBulkPrice Create( - Models::NewPlanCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackageWithMinimumPrice Create( - Models::NewPlanTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithAllocationPrice Create( - Models::NewPlanMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPrice Create( - Models::NewPlanGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePriceProperties/PriceVariants/All.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePriceProperties/PriceVariants/All.cs deleted file mode 100644 index b4511ab8..00000000 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDCreatePlanVersionParamsProperties/ReplacePriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,634 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.ExternalPlanID.ExternalPlanIDCreatePlanVersionParamsProperties.ReplacePriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitPrice(Models::NewPlanUnitPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitPrice From(Models::NewPlanUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanPackagePrice(Models::NewPlanPackagePrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackagePrice From(Models::NewPlanPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanMatrixPrice(Models::NewPlanMatrixPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixPrice From(Models::NewPlanMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPrice(Models::NewPlanTieredPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPrice From(Models::NewPlanTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredBPSPrice(Models::NewPlanTieredBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredBPSPrice From(Models::NewPlanTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBPSPrice(Models::NewPlanBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBPSPrice From(Models::NewPlanBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkBPSPrice(Models::NewPlanBulkBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkBPSPrice From(Models::NewPlanBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkPrice(Models::NewPlanBulkPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkPrice From(Models::NewPlanBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanThresholdTotalAmountPrice, - Models::NewPlanThresholdTotalAmountPrice - >) -)] -public sealed record class NewPlanThresholdTotalAmountPrice( - Models::NewPlanThresholdTotalAmountPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanThresholdTotalAmountPrice From( - Models::NewPlanThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPackagePrice(Models::NewPlanTieredPackagePrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPackagePrice From(Models::NewPlanTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredWithMinimumPrice, - Models::NewPlanTieredWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredWithMinimumPrice( - Models::NewPlanTieredWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredWithMinimumPrice From(Models::NewPlanTieredWithMinimumPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitWithPercentPrice(Models::NewPlanUnitWithPercentPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithPercentPrice From(Models::NewPlanUnitWithPercentPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanPackageWithAllocationPrice, - Models::NewPlanPackageWithAllocationPrice - >) -)] -public sealed record class NewPlanPackageWithAllocationPrice( - Models::NewPlanPackageWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackageWithAllocationPrice From( - Models::NewPlanPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTierWithProrationPrice, - Models::NewPlanTierWithProrationPrice - >) -)] -public sealed record class NewPlanTierWithProrationPrice( - Models::NewPlanTierWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTierWithProrationPrice From(Models::NewPlanTierWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanUnitWithProrationPrice, - Models::NewPlanUnitWithProrationPrice - >) -)] -public sealed record class NewPlanUnitWithProrationPrice( - Models::NewPlanUnitWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithProrationPrice From(Models::NewPlanUnitWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedAllocationPrice, - Models::NewPlanGroupedAllocationPrice - >) -)] -public sealed record class NewPlanGroupedAllocationPrice( - Models::NewPlanGroupedAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedAllocationPrice From(Models::NewPlanGroupedAllocationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithProratedMinimumPrice( - Models::NewPlanGroupedWithProratedMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - > -{ - public static NewPlanGroupedWithProratedMinimumPrice From( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithMeteredMinimumPrice( - Models::NewPlanGroupedWithMeteredMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - > -{ - public static NewPlanGroupedWithMeteredMinimumPrice From( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithDisplayNamePrice, - Models::NewPlanMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewPlanMatrixWithDisplayNamePrice( - Models::NewPlanMatrixWithDisplayNamePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithDisplayNamePrice From( - Models::NewPlanMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanBulkWithProrationPrice, - Models::NewPlanBulkWithProrationPrice - >) -)] -public sealed record class NewPlanBulkWithProrationPrice( - Models::NewPlanBulkWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkWithProrationPrice From(Models::NewPlanBulkWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedTieredPackagePrice, - Models::NewPlanGroupedTieredPackagePrice - >) -)] -public sealed record class NewPlanGroupedTieredPackagePrice( - Models::NewPlanGroupedTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPackagePrice From( - Models::NewPlanGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMaxGroupTieredPackagePrice, - Models::NewPlanMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewPlanMaxGroupTieredPackagePrice( - Models::NewPlanMaxGroupTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMaxGroupTieredPackagePrice From( - Models::NewPlanMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithUnitPricingPrice( - Models::NewPlanScalableMatrixWithUnitPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - > -{ - public static NewPlanScalableMatrixWithUnitPricingPrice From( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithTieredPricingPrice( - Models::NewPlanScalableMatrixWithTieredPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - > -{ - public static NewPlanScalableMatrixWithTieredPricingPrice From( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanCumulativeGroupedBulkPrice, - Models::NewPlanCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewPlanCumulativeGroupedBulkPrice( - Models::NewPlanCumulativeGroupedBulkPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanCumulativeGroupedBulkPrice From( - Models::NewPlanCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredPackageWithMinimumPrice( - Models::NewPlanTieredPackageWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - > -{ - public static NewPlanTieredPackageWithMinimumPrice From( - Models::NewPlanTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithAllocationPrice, - Models::NewPlanMatrixWithAllocationPrice - >) -)] -public sealed record class NewPlanMatrixWithAllocationPrice( - Models::NewPlanMatrixWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithAllocationPrice From( - Models::NewPlanMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanGroupedTieredPrice(Models::NewPlanGroupedTieredPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPrice From(Models::NewPlanGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParams.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParams.cs index 03fc9227..3f39f6e1 100644 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParams.cs +++ b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDFetchPlanVersionParams.cs @@ -1,26 +1,67 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Beta.ExternalPlanID; /// -/// This API endpoint is in beta and its interface may change. It is recommended for -/// use only in test mode. -/// /// This endpoint is used to fetch a plan version. It returns the phases, prices, /// and adjustments present on this version of the plan. /// -public sealed record class ExternalPlanIDFetchPlanVersionParams : Orb::ParamsBase +public sealed record class ExternalPlanIDFetchPlanVersionParams : ParamsBase { - public required string ExternalPlanID; + public required string ExternalPlanID { get; init; } - public required string Version; + public string? Version { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public ExternalPlanIDFetchPlanVersionParams() { } + + public ExternalPlanIDFetchPlanVersionParams( + ExternalPlanIDFetchPlanVersionParams externalPlanIDFetchPlanVersionParams + ) + : base(externalPlanIDFetchPlanVersionParams) { } + + public ExternalPlanIDFetchPlanVersionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPlanIDFetchPlanVersionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPlanIDFetchPlanVersionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/plans/external_plan_id/{0}/versions/{1}", this.ExternalPlanID, @@ -28,16 +69,16 @@ public sealed record class ExternalPlanIDFetchPlanVersionParams : Orb::ParamsBas ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParams.cs b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParams.cs index 09a15732..eeb662fc 100644 --- a/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParams.cs +++ b/src/Orb/Models/Beta/ExternalPlanID/ExternalPlanIDSetDefaultPlanVersionParams.cs @@ -1,71 +1,114 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Beta.ExternalPlanID; /// -/// This API endpoint is in beta and its interface may change. It is recommended for -/// use only in test mode. -/// /// This endpoint allows setting the default version of a plan. /// -public sealed record class ExternalPlanIDSetDefaultPlanVersionParams : Orb::ParamsBase +public sealed record class ExternalPlanIDSetDefaultPlanVersionParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ExternalPlanID; + public string? ExternalPlanID { get; init; } /// /// Plan version to set as the default. /// public required long Version { - get - { - if (!this.BodyProperties.TryGetValue("version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "version", - "Missing required argument" - ); + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "version"); } + init { JsonModel.Set(this._rawBodyData, "version", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["version"] = Json::JsonSerializer.SerializeToElement(value); } + public ExternalPlanIDSetDefaultPlanVersionParams() { } + + public ExternalPlanIDSetDefaultPlanVersionParams( + ExternalPlanIDSetDefaultPlanVersionParams externalPlanIDSetDefaultPlanVersionParams + ) + : base(externalPlanIDSetDefaultPlanVersionParams) + { + this._rawBodyData = [.. externalPlanIDSetDefaultPlanVersionParams._rawBodyData]; + } + + public ExternalPlanIDSetDefaultPlanVersionParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPlanIDSetDefaultPlanVersionParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPlanIDSetDefaultPlanVersionParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/plans/external_plan_id/{0}/set_default_version", this.ExternalPlanID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Beta/PlanVersion.cs b/src/Orb/Models/Beta/PlanVersion.cs index 286a8a79..94622f77 100644 --- a/src/Orb/Models/Beta/PlanVersion.cs +++ b/src/Orb/Models/Beta/PlanVersion.cs @@ -1,10 +1,11 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using Models = Orb.Models; -using Orb = Orb; -using PlanVersionProperties = Orb.Models.Beta.PlanVersionProperties; -using Serialization = System.Text.Json.Serialization; using System = System; namespace Orb.Models.Beta; @@ -13,95 +14,60 @@ namespace Orb.Models.Beta; /// The PlanVersion resource represents the prices and adjustments present on a specific /// version of a plan. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanVersion : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PlanVersion : JsonModel { /// /// Adjustments for this plan. If the plan has phases, this includes adjustments /// across all phases of the plan. /// - public required Generic::List Adjustments + public required IReadOnlyList Adjustments { get { - if (!this.Properties.TryGetValue("adjustments", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustments", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustments"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustments" + ); } - set { this.Properties["adjustments"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustments", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } - public required Generic::List? PlanPhases + public required IReadOnlyList? PlanPhases { get { - if (!this.Properties.TryGetValue("plan_phases", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phases", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>(this.RawData, "plan_phases"); } - set { this.Properties["plan_phases"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "plan_phases", value); } } /// - /// Prices for this plan. If the plan has phases, this includes prices across all - /// phases of the plan. + /// Prices for this plan. If the plan has phases, this includes prices across + /// all phases of the plan. /// - public required Generic::List Prices + public required IReadOnlyList Prices { - get - { - if (!this.Properties.TryGetValue("prices", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "prices", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("prices"); - } - set { this.Properties["prices"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "prices"); } + init { JsonModel.Set(this._rawData, "prices", value); } } public required long Version { - get - { - if (!this.Properties.TryGetValue("version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "version", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["version"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "version"); } + init { JsonModel.Set(this._rawData, "version", value); } } + /// public override void Validate() { foreach (var item in this.Adjustments) @@ -122,18 +88,592 @@ public override void Validate() public PlanVersion() { } + public PlanVersion(PlanVersion planVersion) + : base(planVersion) { } + + public PlanVersion(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanVersion(Generic::Dictionary properties) + [SetsRequiredMembers] + PlanVersion(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static PlanVersion FromRawUnchecked( - Generic::Dictionary properties + /// + public static PlanVersion FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanVersionFromRaw : IFromRawJson +{ + /// + public PlanVersion FromRawUnchecked(IReadOnlyDictionary rawData) => + PlanVersion.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanVersionAdjustmentConverter))] +public record class PlanVersionAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.ID, + planPhaseAmountDiscount: (x) => x.ID, + planPhasePercentageDiscount: (x) => x.ID, + planPhaseMinimum: (x) => x.ID, + planPhaseMaximum: (x) => x.ID + ); + } + } + + public bool IsInvoiceLevel + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.IsInvoiceLevel, + planPhaseAmountDiscount: (x) => x.IsInvoiceLevel, + planPhasePercentageDiscount: (x) => x.IsInvoiceLevel, + planPhaseMinimum: (x) => x.IsInvoiceLevel, + planPhaseMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public long? PlanPhaseOrder + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.PlanPhaseOrder, + planPhaseAmountDiscount: (x) => x.PlanPhaseOrder, + planPhasePercentageDiscount: (x) => x.PlanPhaseOrder, + planPhaseMinimum: (x) => x.PlanPhaseOrder, + planPhaseMaximum: (x) => x.PlanPhaseOrder + ); + } + } + + public string? Reason + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.Reason, + planPhaseAmountDiscount: (x) => x.Reason, + planPhasePercentageDiscount: (x) => x.Reason, + planPhaseMinimum: (x) => x.Reason, + planPhaseMaximum: (x) => x.Reason + ); + } + } + + public string? ReplacesAdjustmentID + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.ReplacesAdjustmentID, + planPhaseAmountDiscount: (x) => x.ReplacesAdjustmentID, + planPhasePercentageDiscount: (x) => x.ReplacesAdjustmentID, + planPhaseMinimum: (x) => x.ReplacesAdjustmentID, + planPhaseMaximum: (x) => x.ReplacesAdjustmentID + ); + } + } + + public PlanVersionAdjustment( + Models::PlanPhaseUsageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanVersionAdjustment( + Models::PlanPhaseAmountDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanVersionAdjustment( + Models::PlanPhasePercentageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanVersionAdjustment( + Models::PlanPhaseMinimumAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanVersionAdjustment( + Models::PlanPhaseMaximumAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanVersionAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseUsageDiscount(out var value)) { + /// // `value` is of type `Models::PlanPhaseUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseUsageDiscount( + [NotNullWhen(true)] out Models::PlanPhaseUsageDiscountAdjustment? value + ) + { + value = this.Value as Models::PlanPhaseUsageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseAmountDiscount(out var value)) { + /// // `value` is of type `Models::PlanPhaseAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseAmountDiscount( + [NotNullWhen(true)] out Models::PlanPhaseAmountDiscountAdjustment? value + ) + { + value = this.Value as Models::PlanPhaseAmountDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhasePercentageDiscount(out var value)) { + /// // `value` is of type `Models::PlanPhasePercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhasePercentageDiscount( + [NotNullWhen(true)] out Models::PlanPhasePercentageDiscountAdjustment? value + ) + { + value = this.Value as Models::PlanPhasePercentageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseMinimum(out var value)) { + /// // `value` is of type `Models::PlanPhaseMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseMinimum( + [NotNullWhen(true)] out Models::PlanPhaseMinimumAdjustment? value + ) + { + value = this.Value as Models::PlanPhaseMinimumAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseMaximum(out var value)) { + /// // `value` is of type `Models::PlanPhaseMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseMaximum( + [NotNullWhen(true)] out Models::PlanPhaseMaximumAdjustment? value + ) + { + value = this.Value as Models::PlanPhaseMaximumAdjustment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (Models::PlanPhaseUsageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseAmountDiscountAdjustment value) => {...}, + /// (Models::PlanPhasePercentageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseMinimumAdjustment value) => {...}, + /// (Models::PlanPhaseMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action planPhaseUsageDiscount, + System::Action planPhaseAmountDiscount, + System::Action planPhasePercentageDiscount, + System::Action planPhaseMinimum, + System::Action planPhaseMaximum + ) + { + switch (this.Value) + { + case Models::PlanPhaseUsageDiscountAdjustment value: + planPhaseUsageDiscount(value); + break; + case Models::PlanPhaseAmountDiscountAdjustment value: + planPhaseAmountDiscount(value); + break; + case Models::PlanPhasePercentageDiscountAdjustment value: + planPhasePercentageDiscount(value); + break; + case Models::PlanPhaseMinimumAdjustment value: + planPhaseMinimum(value); + break; + case Models::PlanPhaseMaximumAdjustment value: + planPhaseMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PlanVersionAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (Models::PlanPhaseUsageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseAmountDiscountAdjustment value) => {...}, + /// (Models::PlanPhasePercentageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseMinimumAdjustment value) => {...}, + /// (Models::PlanPhaseMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func planPhaseUsageDiscount, + System::Func planPhaseAmountDiscount, + System::Func planPhasePercentageDiscount, + System::Func planPhaseMinimum, + System::Func planPhaseMaximum + ) + { + return this.Value switch + { + Models::PlanPhaseUsageDiscountAdjustment value => planPhaseUsageDiscount(value), + Models::PlanPhaseAmountDiscountAdjustment value => planPhaseAmountDiscount(value), + Models::PlanPhasePercentageDiscountAdjustment value => planPhasePercentageDiscount( + value + ), + Models::PlanPhaseMinimumAdjustment value => planPhaseMinimum(value), + Models::PlanPhaseMaximumAdjustment value => planPhaseMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PlanVersionAdjustment" + ), + }; + } + + public static implicit operator PlanVersionAdjustment( + Models::PlanPhaseUsageDiscountAdjustment value + ) => new(value); + + public static implicit operator PlanVersionAdjustment( + Models::PlanPhaseAmountDiscountAdjustment value + ) => new(value); + + public static implicit operator PlanVersionAdjustment( + Models::PlanPhasePercentageDiscountAdjustment value + ) => new(value); + + public static implicit operator PlanVersionAdjustment( + Models::PlanPhaseMinimumAdjustment value + ) => new(value); + + public static implicit operator PlanVersionAdjustment( + Models::PlanPhaseMaximumAdjustment value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PlanVersionAdjustment" + ); + } + this.Switch( + (planPhaseUsageDiscount) => planPhaseUsageDiscount.Validate(), + (planPhaseAmountDiscount) => planPhaseAmountDiscount.Validate(), + (planPhasePercentageDiscount) => planPhasePercentageDiscount.Validate(), + (planPhaseMinimum) => planPhaseMinimum.Validate(), + (planPhaseMaximum) => planPhaseMaximum.Validate() + ); + } + + public virtual bool Equals(PlanVersionAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PlanVersionAdjustmentConverter : JsonConverter +{ + public override PlanVersionAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "usage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PlanVersionAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PlanVersionAdjustment value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Beta/PlanVersionPhase.cs b/src/Orb/Models/Beta/PlanVersionPhase.cs index 7c6a253d..0173afa2 100644 --- a/src/Orb/Models/Beta/PlanVersionPhase.cs +++ b/src/Orb/Models/Beta/PlanVersionPhase.cs @@ -1,42 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanVersionPhaseProperties = Orb.Models.Beta.PlanVersionPhaseProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Beta; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanVersionPhase : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PlanVersionPhase : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } /// @@ -45,47 +30,25 @@ public required string? Description /// public required long? Duration { - get - { - if (!this.Properties.TryGetValue("duration", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "duration"); } + init { JsonModel.Set(this._rawData, "duration", value); } } - public required PlanVersionPhaseProperties::DurationUnit? DurationUnit + public required ApiEnum? DurationUnit { get { - if (!this.Properties.TryGetValue("duration_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "duration_unit"); } - set { this.Properties["duration_unit"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "duration_unit", value); } } public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -93,16 +56,11 @@ public required string Name /// public required long Order { - get - { - if (!this.Properties.TryGetValue("order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("order", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["order"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "order"); } + init { JsonModel.Set(this._rawData, "order", value); } } + /// public override void Validate() { _ = this.ID; @@ -115,18 +73,87 @@ public override void Validate() public PlanVersionPhase() { } + public PlanVersionPhase(PlanVersionPhase planVersionPhase) + : base(planVersionPhase) { } + + public PlanVersionPhase(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanVersionPhase(Generic::Dictionary properties) + [SetsRequiredMembers] + PlanVersionPhase(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanVersionPhase FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanVersionPhaseFromRaw : IFromRawJson +{ + /// + public PlanVersionPhase FromRawUnchecked(IReadOnlyDictionary rawData) => + PlanVersionPhase.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Beta.DurationUnitConverter))] +public enum DurationUnit +{ + Daily, + Monthly, + Quarterly, + SemiAnnual, + Annual, +} + +sealed class DurationUnitConverter : JsonConverter +{ + public override global::Orb.Models.Beta.DurationUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "daily" => global::Orb.Models.Beta.DurationUnit.Daily, + "monthly" => global::Orb.Models.Beta.DurationUnit.Monthly, + "quarterly" => global::Orb.Models.Beta.DurationUnit.Quarterly, + "semi_annual" => global::Orb.Models.Beta.DurationUnit.SemiAnnual, + "annual" => global::Orb.Models.Beta.DurationUnit.Annual, + _ => (global::Orb.Models.Beta.DurationUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Beta.DurationUnit value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Beta.DurationUnit.Daily => "daily", + global::Orb.Models.Beta.DurationUnit.Monthly => "monthly", + global::Orb.Models.Beta.DurationUnit.Quarterly => "quarterly", + global::Orb.Models.Beta.DurationUnit.SemiAnnual => "semi_annual", + global::Orb.Models.Beta.DurationUnit.Annual => "annual", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Beta/PlanVersionPhaseProperties/DurationUnit.cs b/src/Orb/Models/Beta/PlanVersionPhaseProperties/DurationUnit.cs deleted file mode 100644 index 190bb71a..00000000 --- a/src/Orb/Models/Beta/PlanVersionPhaseProperties/DurationUnit.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Beta.PlanVersionPhaseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DurationUnit(string value) : Orb::IEnum -{ - public static readonly DurationUnit Daily = new("daily"); - - public static readonly DurationUnit Monthly = new("monthly"); - - public static readonly DurationUnit Quarterly = new("quarterly"); - - public static readonly DurationUnit SemiAnnual = new("semi_annual"); - - public static readonly DurationUnit Annual = new("annual"); - - readonly string _value = value; - - public enum Value - { - Daily, - Monthly, - Quarterly, - SemiAnnual, - Annual, - } - - public Value Known() => - _value switch - { - "daily" => Value.Daily, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DurationUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Beta/PlanVersionProperties/Adjustment.cs b/src/Orb/Models/Beta/PlanVersionProperties/Adjustment.cs deleted file mode 100644 index 7912e29e..00000000 --- a/src/Orb/Models/Beta/PlanVersionProperties/Adjustment.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AdjustmentVariants = Orb.Models.Beta.PlanVersionProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.PlanVersionProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::PlanPhaseUsageDiscountAdjustment Create( - Models::PlanPhaseUsageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseAmountDiscountAdjustment Create( - Models::PlanPhaseAmountDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhasePercentageDiscountAdjustment Create( - Models::PlanPhasePercentageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseMinimumAdjustment Create( - Models::PlanPhaseMinimumAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseMaximumAdjustment Create( - Models::PlanPhaseMaximumAdjustment value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Beta/PlanVersionProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Beta/PlanVersionProperties/AdjustmentVariants/All.cs deleted file mode 100644 index e25eaff4..00000000 --- a/src/Orb/Models/Beta/PlanVersionProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,120 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PlanVersionProperties = Orb.Models.Beta.PlanVersionProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Beta.PlanVersionProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhaseUsageDiscountAdjustment, - Models::PlanPhaseUsageDiscountAdjustment - >) -)] -public sealed record class PlanPhaseUsageDiscountAdjustment( - Models::PlanPhaseUsageDiscountAdjustment Value -) - : PlanVersionProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseUsageDiscountAdjustment From( - Models::PlanPhaseUsageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhaseAmountDiscountAdjustment, - Models::PlanPhaseAmountDiscountAdjustment - >) -)] -public sealed record class PlanPhaseAmountDiscountAdjustment( - Models::PlanPhaseAmountDiscountAdjustment Value -) - : PlanVersionProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseAmountDiscountAdjustment From( - Models::PlanPhaseAmountDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhasePercentageDiscountAdjustment, - Models::PlanPhasePercentageDiscountAdjustment - >) -)] -public sealed record class PlanPhasePercentageDiscountAdjustment( - Models::PlanPhasePercentageDiscountAdjustment Value -) - : PlanVersionProperties::Adjustment, - Orb::IVariant< - PlanPhasePercentageDiscountAdjustment, - Models::PlanPhasePercentageDiscountAdjustment - > -{ - public static PlanPhasePercentageDiscountAdjustment From( - Models::PlanPhasePercentageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PlanPhaseMinimumAdjustment(Models::PlanPhaseMinimumAdjustment Value) - : PlanVersionProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseMinimumAdjustment From(Models::PlanPhaseMinimumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PlanPhaseMaximumAdjustment(Models::PlanPhaseMaximumAdjustment Value) - : PlanVersionProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseMaximumAdjustment From(Models::PlanPhaseMaximumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/BillableMetricTiny.cs b/src/Orb/Models/BillableMetricTiny.cs index 7244405c..900789eb 100644 --- a/src/Orb/Models/BillableMetricTiny.cs +++ b/src/Orb/Models/BillableMetricTiny.cs @@ -1,28 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BillableMetricTiny : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BillableMetricTiny : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } + /// public override void Validate() { _ = this.ID; @@ -30,18 +24,41 @@ public override void Validate() public BillableMetricTiny() { } + public BillableMetricTiny(BillableMetricTiny billableMetricTiny) + : base(billableMetricTiny) { } + + public BillableMetricTiny(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BillableMetricTiny(Generic::Dictionary properties) + [SetsRequiredMembers] + BillableMetricTiny(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BillableMetricTiny FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BillableMetricTiny(string id) + : this() + { + this.ID = id; } } + +class BillableMetricTinyFromRaw : IFromRawJson +{ + /// + public BillableMetricTiny FromRawUnchecked(IReadOnlyDictionary rawData) => + BillableMetricTiny.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/BillingCycleAnchorConfiguration.cs b/src/Orb/Models/BillingCycleAnchorConfiguration.cs index c87da2f2..9baf7f4a 100644 --- a/src/Orb/Models/BillingCycleAnchorConfiguration.cs +++ b/src/Orb/Models/BillingCycleAnchorConfiguration.cs @@ -1,33 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BillingCycleAnchorConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + BillingCycleAnchorConfiguration, + BillingCycleAnchorConfigurationFromRaw + >) +)] +public sealed record class BillingCycleAnchorConfiguration : JsonModel { /// /// The day of the month on which the billing cycle is anchored. If the maximum - /// number of days in a month is greater than this value, the last day of the month - /// is the billing cycle day (e.g. billing_cycle_day=31 for April means the billing - /// period begins on the 30th. + /// number of days in a month is greater than this value, the last day of the + /// month is the billing cycle day (e.g. billing_cycle_day=31 for April means + /// the billing period begins on the 30th. /// public required long Day { - get - { - if (!this.Properties.TryGetValue("day", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("day", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["day"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "day"); } + init { JsonModel.Set(this._rawData, "day", value); } } /// @@ -36,14 +33,8 @@ public required long Day /// public long? Month { - get - { - if (!this.Properties.TryGetValue("month", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["month"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "month"); } + init { JsonModel.Set(this._rawData, "month", value); } } /// @@ -52,16 +43,11 @@ public long? Month /// public long? Year { - get - { - if (!this.Properties.TryGetValue("year", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["year"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "year"); } + init { JsonModel.Set(this._rawData, "year", value); } } + /// public override void Validate() { _ = this.Day; @@ -71,18 +57,44 @@ public override void Validate() public BillingCycleAnchorConfiguration() { } + public BillingCycleAnchorConfiguration( + BillingCycleAnchorConfiguration billingCycleAnchorConfiguration + ) + : base(billingCycleAnchorConfiguration) { } + + public BillingCycleAnchorConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BillingCycleAnchorConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + BillingCycleAnchorConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BillingCycleAnchorConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BillingCycleAnchorConfiguration(long day) + : this() + { + this.Day = day; } } + +class BillingCycleAnchorConfigurationFromRaw : IFromRawJson +{ + /// + public BillingCycleAnchorConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BillingCycleAnchorConfiguration.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/BillingCycleConfiguration.cs b/src/Orb/Models/BillingCycleConfiguration.cs index 7394e479..aad734ec 100644 --- a/src/Orb/Models/BillingCycleConfiguration.cs +++ b/src/Orb/Models/BillingCycleConfiguration.cs @@ -1,50 +1,38 @@ -using BillingCycleConfigurationProperties = Orb.Models.BillingCycleConfigurationProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BillingCycleConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class BillingCycleConfiguration : JsonModel { public required long Duration { - get - { - if (!this.Properties.TryGetValue("duration", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "duration"); } + init { JsonModel.Set(this._rawData, "duration", value); } } - public required BillingCycleConfigurationProperties::DurationUnit DurationUnit + public required ApiEnum DurationUnit { get { - if (!this.Properties.TryGetValue("duration_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("duration_unit"); + return JsonModel.GetNotNullClass>( + this.RawData, + "duration_unit" + ); } - set { this.Properties["duration_unit"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "duration_unit", value); } } + /// public override void Validate() { _ = this.Duration; @@ -53,18 +41,79 @@ public override void Validate() public BillingCycleConfiguration() { } + public BillingCycleConfiguration(BillingCycleConfiguration billingCycleConfiguration) + : base(billingCycleConfiguration) { } + + public BillingCycleConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BillingCycleConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + BillingCycleConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BillingCycleConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BillingCycleConfigurationFromRaw : IFromRawJson +{ + /// + public BillingCycleConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BillingCycleConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DurationUnitConverter))] +public enum DurationUnit +{ + Day, + Month, +} + +sealed class DurationUnitConverter : JsonConverter +{ + public override DurationUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => DurationUnit.Day, + "month" => DurationUnit.Month, + _ => (DurationUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + DurationUnit value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + DurationUnit.Day => "day", + DurationUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/BillingCycleConfigurationProperties/DurationUnit.cs b/src/Orb/Models/BillingCycleConfigurationProperties/DurationUnit.cs deleted file mode 100644 index 30616f2c..00000000 --- a/src/Orb/Models/BillingCycleConfigurationProperties/DurationUnit.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.BillingCycleConfigurationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DurationUnit(string value) : Orb::IEnum -{ - public static readonly DurationUnit Day = new("day"); - - public static readonly DurationUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DurationUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/BillingCycleRelativeDate.cs b/src/Orb/Models/BillingCycleRelativeDate.cs index 1290616e..f1dbe2a8 100644 --- a/src/Orb/Models/BillingCycleRelativeDate.cs +++ b/src/Orb/Models/BillingCycleRelativeDate.cs @@ -1,45 +1,50 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class BillingCycleRelativeDate(string value) - : Orb::IEnum +[JsonConverter(typeof(BillingCycleRelativeDateConverter))] +public enum BillingCycleRelativeDate { - public static readonly BillingCycleRelativeDate StartOfTerm = new("start_of_term"); - - public static readonly BillingCycleRelativeDate EndOfTerm = new("end_of_term"); - - readonly string _value = value; + StartOfTerm, + EndOfTerm, +} - public enum Value +sealed class BillingCycleRelativeDateConverter : JsonConverter +{ + public override BillingCycleRelativeDate Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) { - StartOfTerm, - EndOfTerm, - } - - public Value Known() => - _value switch + return JsonSerializer.Deserialize(ref reader, options) switch { - "start_of_term" => Value.StartOfTerm, - "end_of_term" => Value.EndOfTerm, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), + "start_of_term" => BillingCycleRelativeDate.StartOfTerm, + "end_of_term" => BillingCycleRelativeDate.EndOfTerm, + _ => (BillingCycleRelativeDate)(-1), }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); } - public static BillingCycleRelativeDate FromRaw(string value) + public override void Write( + Utf8JsonWriter writer, + BillingCycleRelativeDate value, + JsonSerializerOptions options + ) { - return new(value); + JsonSerializer.Serialize( + writer, + value switch + { + BillingCycleRelativeDate.StartOfTerm => "start_of_term", + BillingCycleRelativeDate.EndOfTerm => "end_of_term", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/BulkBPSConfig.cs b/src/Orb/Models/BulkBPSConfig.cs deleted file mode 100644 index cd7e2c3e..00000000 --- a/src/Orb/Models/BulkBPSConfig.cs +++ /dev/null @@ -1,54 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BulkBPSConfig : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Tiers for a bulk BPS pricing model where all usage is aggregated to a single - /// tier based on total volume - /// - public required Generic::List Tiers - { - get - { - if (!this.Properties.TryGetValue("tiers", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("tiers", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tiers"); - } - set { this.Properties["tiers"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - foreach (var item in this.Tiers) - { - item.Validate(); - } - } - - public BulkBPSConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BulkBPSConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BulkBPSConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/BulkBPSTier.cs b/src/Orb/Models/BulkBPSTier.cs deleted file mode 100644 index 6884146c..00000000 --- a/src/Orb/Models/BulkBPSTier.cs +++ /dev/null @@ -1,84 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BulkBPSTier : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Basis points to rate on - /// - public required double BPS - { - get - { - if (!this.Properties.TryGetValue("bps", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("bps", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["bps"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Upper bound for tier - /// - public string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The maximum amount to charge for any one event - /// - public string? PerUnitMaximum - { - get - { - if (!this.Properties.TryGetValue("per_unit_maximum", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_maximum"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.BPS; - _ = this.MaximumAmount; - _ = this.PerUnitMaximum; - } - - public BulkBPSTier() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BulkBPSTier(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BulkBPSTier FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/BulkConfig.cs b/src/Orb/Models/BulkConfig.cs index 64bbdd89..8ae30c9c 100644 --- a/src/Orb/Models/BulkConfig.cs +++ b/src/Orb/Models/BulkConfig.cs @@ -1,31 +1,28 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BulkConfig : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for bulk pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BulkConfig : JsonModel { /// /// Bulk tiers for rating based on total usage volume /// - public required Generic::List Tiers + public required IReadOnlyList Tiers { - get - { - if (!this.Properties.TryGetValue("tiers", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("tiers", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tiers"); - } - set { this.Properties["tiers"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "tiers"); } + init { JsonModel.Set(this._rawData, "tiers", value); } } + /// public override void Validate() { foreach (var item in this.Tiers) @@ -36,18 +33,39 @@ public override void Validate() public BulkConfig() { } + public BulkConfig(BulkConfig bulkConfig) + : base(bulkConfig) { } + + public BulkConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BulkConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + BulkConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static BulkConfig FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static BulkConfig FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public BulkConfig(List tiers) + : this() + { + this.Tiers = tiers; + } +} + +class BulkConfigFromRaw : IFromRawJson +{ + /// + public BulkConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + BulkConfig.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/BulkTier.cs b/src/Orb/Models/BulkTier.cs index a5f831cd..d766c239 100644 --- a/src/Orb/Models/BulkTier.cs +++ b/src/Orb/Models/BulkTier.cs @@ -1,32 +1,25 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BulkTier : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BulkTier : JsonModel { /// /// Amount per unit /// public required string UnitAmount { - get - { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); - } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } } /// @@ -34,16 +27,11 @@ public required string UnitAmount /// public double? MaximumUnits { - get - { - if (!this.Properties.TryGetValue("maximum_units", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_units"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "maximum_units"); } + init { JsonModel.Set(this._rawData, "maximum_units", value); } } + /// public override void Validate() { _ = this.UnitAmount; @@ -52,18 +40,39 @@ public override void Validate() public BulkTier() { } + public BulkTier(BulkTier bulkTier) + : base(bulkTier) { } + + public BulkTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BulkTier(Generic::Dictionary properties) + [SetsRequiredMembers] + BulkTier(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static BulkTier FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static BulkTier FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public BulkTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class BulkTierFromRaw : IFromRawJson +{ + /// + public BulkTier FromRawUnchecked(IReadOnlyDictionary rawData) => + BulkTier.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/ChangedSubscriptionResources.cs b/src/Orb/Models/ChangedSubscriptionResources.cs index 4f43a667..35aa724e 100644 --- a/src/Orb/Models/ChangedSubscriptionResources.cs +++ b/src/Orb/Models/ChangedSubscriptionResources.cs @@ -1,104 +1,74 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ChangedSubscriptionResources - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ChangedSubscriptionResources : JsonModel { /// /// The credit notes that were created as part of this operation. /// - public required Generic::List CreatedCreditNotes + public required IReadOnlyList CreatedCreditNotes { get { - if (!this.Properties.TryGetValue("created_credit_notes", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_credit_notes", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("created_credit_notes"); - } - set - { - this.Properties["created_credit_notes"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass>( + this.RawData, + "created_credit_notes" ); } + init { JsonModel.Set(this._rawData, "created_credit_notes", value); } } /// /// The invoices that were created as part of this operation. /// - public required Generic::List CreatedInvoices + public required IReadOnlyList CreatedInvoices { get { - if (!this.Properties.TryGetValue("created_invoices", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_invoices", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("created_invoices"); - } - set - { - this.Properties["created_invoices"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "created_invoices" + ); } + init { JsonModel.Set(this._rawData, "created_invoices", value); } } /// /// The credit notes that were voided as part of this operation. /// - public required Generic::List VoidedCreditNotes + public required IReadOnlyList VoidedCreditNotes { get { - if (!this.Properties.TryGetValue("voided_credit_notes", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_credit_notes", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("voided_credit_notes"); - } - set - { - this.Properties["voided_credit_notes"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "voided_credit_notes" + ); } + init { JsonModel.Set(this._rawData, "voided_credit_notes", value); } } /// /// The invoices that were voided as part of this operation. /// - public required Generic::List VoidedInvoices + public required IReadOnlyList VoidedInvoices { - get - { - if (!this.Properties.TryGetValue("voided_invoices", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_invoices", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("voided_invoices"); - } - set { this.Properties["voided_invoices"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "voided_invoices"); } + init { JsonModel.Set(this._rawData, "voided_invoices", value); } } + /// public override void Validate() { foreach (var item in this.CreatedCreditNotes) @@ -121,18 +91,2519 @@ public override void Validate() public ChangedSubscriptionResources() { } + public ChangedSubscriptionResources(ChangedSubscriptionResources changedSubscriptionResources) + : base(changedSubscriptionResources) { } + + public ChangedSubscriptionResources(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ChangedSubscriptionResources(Generic::Dictionary properties) + [SetsRequiredMembers] + ChangedSubscriptionResources(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static ChangedSubscriptionResources FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ChangedSubscriptionResourcesFromRaw : IFromRawJson +{ + /// + public ChangedSubscriptionResources FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ChangedSubscriptionResources.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CreatedInvoice : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// This is the final amount required to be charged to the customer and reflects + /// the application of the customer balance to the `total` of the invoice. + /// + public required string AmountDue + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount_due"); } + init { JsonModel.Set(this._rawData, "amount_due", value); } + } + + public required AutoCollection AutoCollection + { + get { return JsonModel.GetNotNullClass(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } + } + + public required Address? BillingAddress + { + get { return JsonModel.GetNullableClass
(this.RawData, "billing_address"); } + init { JsonModel.Set(this._rawData, "billing_address", value); } + } + + /// + /// The creation time of the resource in Orb. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + /// + /// A list of credit notes associated with the invoice + /// + public required IReadOnlyList CreditNotes + { + get { return JsonModel.GetNotNullClass>(this.RawData, "credit_notes"); } + init { JsonModel.Set(this._rawData, "credit_notes", value); } + } + + /// + /// An ISO 4217 currency string or `credits` + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + public required CustomerMinified Customer + { + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } + } + + public required IReadOnlyList CustomerBalanceTransactions + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "customer_balance_transactions" + ); + } + init { JsonModel.Set(this._rawData, "customer_balance_transactions", value); } + } + + /// + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. + /// + /// ### Supported Tax ID Countries and Types + /// + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + /// + public required CustomerTaxID? CustomerTaxID + { + get { return JsonModel.GetNullableClass(this.RawData, "customer_tax_id"); } + init { JsonModel.Set(this._rawData, "customer_tax_id", value); } + } + + /// + /// This field is deprecated in favor of `discounts`. If a `discounts` list is + /// provided, the first discount in the list will be returned. If the list is + /// empty, `None` will be returned. + /// + [System::Obsolete("deprecated")] + public required JsonElement Discount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required IReadOnlyList Discounts + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "discounts"); + } + init { JsonModel.Set(this._rawData, "discounts", value); } + } + + /// + /// When the invoice payment is due. The due date is null if the invoice is not + /// yet finalized. + /// + public required System::DateTimeOffset? DueDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "due_date"); + } + init { JsonModel.Set(this._rawData, "due_date", value); } + } + + /// + /// If the invoice has a status of `draft`, this will be the time that the invoice + /// will be eligible to be issued, otherwise it will be `null`. If `auto-issue` + /// is true, the invoice will automatically begin issuing at this time. + /// + public required System::DateTimeOffset? EligibleToIssueAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "eligible_to_issue_at" + ); + } + init { JsonModel.Set(this._rawData, "eligible_to_issue_at", value); } + } + + /// + /// A URL for the customer-facing invoice portal. This URL expires 30 days after + /// the invoice's due date, or 60 days after being re-generated through the UI. + /// + public required string? HostedInvoiceURL + { + get { return JsonModel.GetNullableClass(this.RawData, "hosted_invoice_url"); } + init { JsonModel.Set(this._rawData, "hosted_invoice_url", value); } + } + + /// + /// The scheduled date of the invoice + /// + public required System::DateTimeOffset InvoiceDate + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "invoice_date"); + } + init { JsonModel.Set(this._rawData, "invoice_date", value); } + } + + /// + /// Automatically generated invoice number to help track and reconcile invoices. + /// Invoice numbers have a prefix such as `RFOBWG`. These can be sequential per + /// account or customer. + /// + public required string InvoiceNumber + { + get { return JsonModel.GetNotNullClass(this.RawData, "invoice_number"); } + init { JsonModel.Set(this._rawData, "invoice_number", value); } + } + + /// + /// The link to download the PDF representation of the `Invoice`. + /// + public required string? InvoicePdf + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_pdf"); } + init { JsonModel.Set(this._rawData, "invoice_pdf", value); } + } + + public required ApiEnum InvoiceSource + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "invoice_source" + ); + } + init { JsonModel.Set(this._rawData, "invoice_source", value); } + } + + /// + /// True if the invoice has only in-advance fixed fees and is payable now + /// + public required bool IsPayableNow + { + get { return JsonModel.GetNotNullStruct(this.RawData, "is_payable_now"); } + init { JsonModel.Set(this._rawData, "is_payable_now", value); } + } + + /// + /// If the invoice failed to issue, this will be the last time it failed to issue + /// (even if it is now in a different state.) + /// + public required System::DateTimeOffset? IssueFailedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "issue_failed_at" + ); + } + init { JsonModel.Set(this._rawData, "issue_failed_at", value); } + } + + /// + /// If the invoice has been issued, this will be the time it transitioned to + /// `issued` (even if it is now in a different state.) + /// + public required System::DateTimeOffset? IssuedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "issued_at"); + } + init { JsonModel.Set(this._rawData, "issued_at", value); } + } + + /// + /// The breakdown of prices in this invoice. + /// + public required IReadOnlyList LineItems + { + get { return JsonModel.GetNotNullClass>(this.RawData, "line_items"); } + init { JsonModel.Set(this._rawData, "line_items", value); } + } + + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// Free-form text which is available on the invoice PDF and the Orb invoice portal. + /// + public required string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// If the invoice has a status of `paid`, this gives a timestamp when the invoice + /// was paid. + /// + public required System::DateTimeOffset? PaidAt + { + get { return JsonModel.GetNullableStruct(this.RawData, "paid_at"); } + init { JsonModel.Set(this._rawData, "paid_at", value); } + } + + /// + /// A list of payment attempts associated with the invoice + /// + public required IReadOnlyList PaymentAttempts + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "payment_attempts" + ); + } + init { JsonModel.Set(this._rawData, "payment_attempts", value); } + } + + /// + /// If payment was attempted on this invoice but failed, this will be the time + /// of the most recent attempt. + /// + public required System::DateTimeOffset? PaymentFailedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "payment_failed_at" + ); + } + init { JsonModel.Set(this._rawData, "payment_failed_at", value); } + } + + /// + /// If payment was attempted on this invoice, this will be the start time of + /// the most recent attempt. This field is especially useful for delayed-notification + /// payment mechanisms (like bank transfers), where payment can take 3 days or more. + /// + public required System::DateTimeOffset? PaymentStartedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "payment_started_at" + ); + } + init { JsonModel.Set(this._rawData, "payment_started_at", value); } + } + + /// + /// If the invoice is in draft, this timestamp will reflect when the invoice is + /// scheduled to be issued. + /// + public required System::DateTimeOffset? ScheduledIssueAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "scheduled_issue_at" + ); + } + init { JsonModel.Set(this._rawData, "scheduled_issue_at", value); } + } + + public required Address? ShippingAddress + { + get { return JsonModel.GetNullableClass
(this.RawData, "shipping_address"); } + init { JsonModel.Set(this._rawData, "shipping_address", value); } + } + + public required ApiEnum Status + { + get { return JsonModel.GetNotNullClass>(this.RawData, "status"); } + init { JsonModel.Set(this._rawData, "status", value); } + } + + public required SubscriptionMinified? Subscription + { + get + { + return JsonModel.GetNullableClass(this.RawData, "subscription"); + } + init { JsonModel.Set(this._rawData, "subscription", value); } + } + + /// + /// The total before any discounts and minimums are applied. + /// + public required string Subtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } + + /// + /// If the invoice failed to sync, this will be the last time an external invoicing + /// provider sync was attempted. This field will always be `null` for invoices + /// using Orb Invoicing. + /// + public required System::DateTimeOffset? SyncFailedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "sync_failed_at" + ); + } + init { JsonModel.Set(this._rawData, "sync_failed_at", value); } + } + + /// + /// The total after any minimums and discounts have been applied. + /// + public required string Total + { + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } + } + + /// + /// If the invoice has a status of `void`, this gives a timestamp when the invoice + /// was voided. + /// + public required System::DateTimeOffset? VoidedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); + } + init { JsonModel.Set(this._rawData, "voided_at", value); } + } + + /// + /// This is true if the invoice will be automatically issued in the future, and + /// false otherwise. + /// + public required bool WillAutoIssue + { + get { return JsonModel.GetNotNullStruct(this.RawData, "will_auto_issue"); } + init { JsonModel.Set(this._rawData, "will_auto_issue", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.AmountDue; + this.AutoCollection.Validate(); + this.BillingAddress?.Validate(); + _ = this.CreatedAt; + foreach (var item in this.CreditNotes) + { + item.Validate(); + } + _ = this.Currency; + this.Customer.Validate(); + foreach (var item in this.CustomerBalanceTransactions) + { + item.Validate(); + } + this.CustomerTaxID?.Validate(); + _ = this.Discount; + foreach (var item in this.Discounts) + { + item.Validate(); + } + _ = this.DueDate; + _ = this.EligibleToIssueAt; + _ = this.HostedInvoiceURL; + _ = this.InvoiceDate; + _ = this.InvoiceNumber; + _ = this.InvoicePdf; + this.InvoiceSource.Validate(); + _ = this.IsPayableNow; + _ = this.IssueFailedAt; + _ = this.IssuedAt; + foreach (var item in this.LineItems) + { + item.Validate(); + } + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Memo; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + _ = this.PaidAt; + foreach (var item in this.PaymentAttempts) + { + item.Validate(); + } + _ = this.PaymentFailedAt; + _ = this.PaymentStartedAt; + _ = this.ScheduledIssueAt; + this.ShippingAddress?.Validate(); + this.Status.Validate(); + this.Subscription?.Validate(); + _ = this.Subtotal; + _ = this.SyncFailedAt; + _ = this.Total; + _ = this.VoidedAt; + _ = this.WillAutoIssue; + } + + [System::Obsolete("Required properties are deprecated: discount")] + public CreatedInvoice() { } + + [System::Obsolete("Required properties are deprecated: discount")] + public CreatedInvoice(CreatedInvoice createdInvoice) + : base(createdInvoice) { } + + [System::Obsolete("Required properties are deprecated: discount")] + public CreatedInvoice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [System::Obsolete("Required properties are deprecated: discount")] + [SetsRequiredMembers] + CreatedInvoice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CreatedInvoice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreatedInvoiceFromRaw : IFromRawJson +{ + /// + public CreatedInvoice FromRawUnchecked(IReadOnlyDictionary rawData) => + CreatedInvoice.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AutoCollection : JsonModel +{ + /// + /// True only if auto-collection is enabled for this invoice. + /// + public required bool? Enabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "enabled"); } + init { JsonModel.Set(this._rawData, "enabled", value); } + } + + /// + /// If the invoice is scheduled for auto-collection, this field will reflect when + /// the next attempt will occur. If dunning has been exhausted, or auto-collection + /// is not enabled for this invoice, this field will be `null`. + /// + public required System::DateTimeOffset? NextAttemptAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "next_attempt_at" + ); + } + init { JsonModel.Set(this._rawData, "next_attempt_at", value); } + } + + /// + /// Number of auto-collection payment attempts. + /// + public required long? NumAttempts + { + get { return JsonModel.GetNullableStruct(this.RawData, "num_attempts"); } + init { JsonModel.Set(this._rawData, "num_attempts", value); } + } + + /// + /// If Orb has ever attempted payment auto-collection for this invoice, this field + /// will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + /// this can be used to tell whether the invoice is currently in dunning (that + /// is, `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), + /// or if dunning has been exhausted (`previously_attempted_at` is non-null, but + /// `next_attempt_time` is null). + /// + public required System::DateTimeOffset? PreviouslyAttemptedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "previously_attempted_at" + ); + } + init { JsonModel.Set(this._rawData, "previously_attempted_at", value); } + } + + /// + public override void Validate() + { + _ = this.Enabled; + _ = this.NextAttemptAt; + _ = this.NumAttempts; + _ = this.PreviouslyAttemptedAt; + } + + public AutoCollection() { } + + public AutoCollection(AutoCollection autoCollection) + : base(autoCollection) { } + + public AutoCollection(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AutoCollection(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AutoCollection FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AutoCollectionFromRaw : IFromRawJson +{ + /// + public AutoCollection FromRawUnchecked(IReadOnlyDictionary rawData) => + AutoCollection.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CreditNote : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string CreditNoteNumber + { + get { return JsonModel.GetNotNullClass(this.RawData, "credit_note_number"); } + init { JsonModel.Set(this._rawData, "credit_note_number", value); } + } + + /// + /// An optional memo supplied on the credit note. + /// + public required string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + public required string Reason + { + get { return JsonModel.GetNotNullClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + public required string Total + { + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } + } + + public required string Type + { + get { return JsonModel.GetNotNullClass(this.RawData, "type"); } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + /// If the credit note has a status of `void`, this gives a timestamp when the + /// credit note was voided. + /// + public required System::DateTimeOffset? VoidedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); + } + init { JsonModel.Set(this._rawData, "voided_at", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CreditNoteNumber; + _ = this.Memo; + _ = this.Reason; + _ = this.Total; + _ = this.Type; + _ = this.VoidedAt; + } + + public CreditNote() { } + + public CreditNote(CreditNote creditNote) + : base(creditNote) { } + + public CreditNote(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditNote(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CreditNote FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreditNoteFromRaw : IFromRawJson +{ + /// + public CreditNote FromRawUnchecked(IReadOnlyDictionary rawData) => + CreditNote.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CustomerBalanceTransaction : JsonModel +{ + /// + /// A unique id for this transaction. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required ApiEnum Action + { + get { return JsonModel.GetNotNullClass>(this.RawData, "action"); } + init { JsonModel.Set(this._rawData, "action", value); } + } + + /// + /// The value of the amount changed in the transaction. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The creation time of this transaction. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required CreditNoteTiny? CreditNote + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_note"); } + init { JsonModel.Set(this._rawData, "credit_note", value); } + } + + /// + /// An optional description provided for manual customer balance adjustments. + /// + public required string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// The new value of the customer's balance prior to the transaction, in the customer's currency. + /// + public required string EndingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } + } + + public required InvoiceTiny? Invoice + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice"); } + init { JsonModel.Set(this._rawData, "invoice", value); } + } + + /// + /// The original value of the customer's balance prior to the transaction, in + /// the customer's currency. + /// + public required string StartingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } + } + + public required ApiEnum Type + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); + } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.Action.Validate(); + _ = this.Amount; + _ = this.CreatedAt; + this.CreditNote?.Validate(); + _ = this.Description; + _ = this.EndingBalance; + this.Invoice?.Validate(); + _ = this.StartingBalance; + this.Type.Validate(); + } + + public CustomerBalanceTransaction() { } + + public CustomerBalanceTransaction(CustomerBalanceTransaction customerBalanceTransaction) + : base(customerBalanceTransaction) { } + + public CustomerBalanceTransaction(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerBalanceTransaction(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerBalanceTransaction FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerBalanceTransactionFromRaw : IFromRawJson +{ + /// + public CustomerBalanceTransaction FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerBalanceTransaction.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ActionConverter))] +public enum Action +{ + AppliedToInvoice, + ManualAdjustment, + ProratedRefund, + RevertProratedRefund, + ReturnFromVoiding, + CreditNoteApplied, + CreditNoteVoided, + OverpaymentRefund, + ExternalPayment, + SmallInvoiceCarryover, +} + +sealed class ActionConverter : JsonConverter +{ + public override Action Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "applied_to_invoice" => Action.AppliedToInvoice, + "manual_adjustment" => Action.ManualAdjustment, + "prorated_refund" => Action.ProratedRefund, + "revert_prorated_refund" => Action.RevertProratedRefund, + "return_from_voiding" => Action.ReturnFromVoiding, + "credit_note_applied" => Action.CreditNoteApplied, + "credit_note_voided" => Action.CreditNoteVoided, + "overpayment_refund" => Action.OverpaymentRefund, + "external_payment" => Action.ExternalPayment, + "small_invoice_carryover" => Action.SmallInvoiceCarryover, + _ => (Action)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Action value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Action.AppliedToInvoice => "applied_to_invoice", + Action.ManualAdjustment => "manual_adjustment", + Action.ProratedRefund => "prorated_refund", + Action.RevertProratedRefund => "revert_prorated_refund", + Action.ReturnFromVoiding => "return_from_voiding", + Action.CreditNoteApplied => "credit_note_applied", + Action.CreditNoteVoided => "credit_note_voided", + Action.OverpaymentRefund => "overpayment_refund", + Action.ExternalPayment => "external_payment", + Action.SmallInvoiceCarryover => "small_invoice_carryover", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TypeConverter))] +public enum Type +{ + Increment, + Decrement, +} + +sealed class TypeConverter : JsonConverter +{ + public override global::Orb.Models.Type Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => global::Orb.Models.Type.Increment, + "decrement" => global::Orb.Models.Type.Decrement, + _ => (global::Orb.Models.Type)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Type value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Type.Increment => "increment", + global::Orb.Models.Type.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(InvoiceSourceConverter))] +public enum InvoiceSource +{ + Subscription, + Partial, + OneOff, +} + +sealed class InvoiceSourceConverter : JsonConverter +{ + public override InvoiceSource Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "subscription" => InvoiceSource.Subscription, + "partial" => InvoiceSource.Partial, + "one_off" => InvoiceSource.OneOff, + _ => (InvoiceSource)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceSource value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + InvoiceSource.Subscription => "subscription", + InvoiceSource.Partial => "partial", + InvoiceSource.OneOff => "one_off", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class LineItem : JsonModel +{ + /// + /// A unique ID for this line item. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The line amount after any adjustments and before overage conversion, credits + /// and partial invoicing. + /// + public required string AdjustedSubtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjusted_subtotal"); } + init { JsonModel.Set(this._rawData, "adjusted_subtotal", value); } + } + + /// + /// All adjustments applied to the line item in the order they were applied based + /// on invoice calculations (ie. usage discounts -> amount discounts -> percentage + /// discounts -> minimums -> maximums). + /// + public required IReadOnlyList Adjustments + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "adjustments"); + } + init { JsonModel.Set(this._rawData, "adjustments", value); } + } + + /// + /// The final amount for a line item after all adjustments and pre paid credits + /// have been applied. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The number of prepaid credits applied. + /// + public required string CreditsApplied + { + get { return JsonModel.GetNotNullClass(this.RawData, "credits_applied"); } + init { JsonModel.Set(this._rawData, "credits_applied", value); } + } + + /// + /// The end date of the range of time applied for this line item's price. + /// + public required System::DateTimeOffset EndDate + { + get { return JsonModel.GetNotNullStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// An additional filter that was used to calculate the usage for this line item. + /// + public required string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// [DEPRECATED] For configured prices that are split by a grouping key, this + /// will be populated with the key and a value. The `amount` and `subtotal` will + /// be the values for this particular grouping. + /// + public required string? Grouping + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } + } + + /// + /// The name of the price associated with this line item. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Any amount applied from a partial invoice + /// + public required string PartiallyInvoicedAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "partially_invoiced_amount"); } + init { JsonModel.Set(this._rawData, "partially_invoiced_amount", value); } + } + + /// + /// The Price resource represents a price that can be billed on a subscription, + /// resulting in a charge on an invoice in the form of an invoice line item. + /// Prices take a quantity and determine an amount to bill. + /// + /// Orb supports a few different pricing models out of the box. Each of + /// these models is serialized differently in a given Price object. The model_type + /// field determines the key for the configuration object that is present. + /// + /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + /// + public required Price Price + { + get { return JsonModel.GetNotNullClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// Either the fixed fee quantity or the usage during the service period. + /// + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + /// The start date of the range of time applied for this line item's price. + /// + public required System::DateTimeOffset StartDate + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); + } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + /// For complex pricing structures, the line item can be broken down further + /// in `sub_line_items`. + /// + public required IReadOnlyList SubLineItems + { + get { return JsonModel.GetNotNullClass>(this.RawData, "sub_line_items"); } + init { JsonModel.Set(this._rawData, "sub_line_items", value); } + } + + /// + /// The line amount before any adjustments. + /// + public required string Subtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } + + /// + /// An array of tax rates and their incurred tax amounts. Empty if no tax integration + /// is configured. + /// + public required IReadOnlyList TaxAmounts + { + get { return JsonModel.GetNotNullClass>(this.RawData, "tax_amounts"); } + init { JsonModel.Set(this._rawData, "tax_amounts", value); } + } + + /// + /// A list of customer ids that were used to calculate the usage for this line item. + /// + public required IReadOnlyList? UsageCustomerIDs + { + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.AdjustedSubtotal; + foreach (var item in this.Adjustments) + { + item.Validate(); + } + _ = this.Amount; + _ = this.CreditsApplied; + _ = this.EndDate; + _ = this.Filter; + _ = this.Grouping; + _ = this.Name; + _ = this.PartiallyInvoicedAmount; + this.Price.Validate(); + _ = this.Quantity; + _ = this.StartDate; + foreach (var item in this.SubLineItems) + { + item.Validate(); + } + _ = this.Subtotal; + foreach (var item in this.TaxAmounts) + { + item.Validate(); + } + _ = this.UsageCustomerIDs; + } + + public LineItem() { } + + public LineItem(LineItem lineItem) + : base(lineItem) { } + + public LineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LineItem FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class LineItemFromRaw : IFromRawJson +{ + /// + public LineItem FromRawUnchecked(IReadOnlyDictionary rawData) => + LineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(LineItemAdjustmentConverter))] +public record class LineItemAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ID, + monetaryAmountDiscount: (x) => x.ID, + monetaryPercentageDiscount: (x) => x.ID, + monetaryMinimum: (x) => x.ID, + monetaryMaximum: (x) => x.ID + ); + } + } + + public string Amount + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.Amount, + monetaryAmountDiscount: (x) => x.Amount, + monetaryPercentageDiscount: (x) => x.Amount, + monetaryMinimum: (x) => x.Amount, + monetaryMaximum: (x) => x.Amount + ); + } + } + + public bool IsInvoiceLevel + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.IsInvoiceLevel, + monetaryAmountDiscount: (x) => x.IsInvoiceLevel, + monetaryPercentageDiscount: (x) => x.IsInvoiceLevel, + monetaryMinimum: (x) => x.IsInvoiceLevel, + monetaryMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public string? Reason + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.Reason, + monetaryAmountDiscount: (x) => x.Reason, + monetaryPercentageDiscount: (x) => x.Reason, + monetaryMinimum: (x) => x.Reason, + monetaryMaximum: (x) => x.Reason + ); + } + } + + public string? ReplacesAdjustmentID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryAmountDiscount: (x) => x.ReplacesAdjustmentID, + monetaryPercentageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryMinimum: (x) => x.ReplacesAdjustmentID, + monetaryMaximum: (x) => x.ReplacesAdjustmentID + ); + } + } + + public LineItemAdjustment(MonetaryUsageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LineItemAdjustment(MonetaryAmountDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LineItemAdjustment( + MonetaryPercentageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LineItemAdjustment(MonetaryMinimumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LineItemAdjustment(MonetaryMaximumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LineItemAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryUsageDiscount(out var value)) { + /// // `value` is of type `MonetaryUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryUsageDiscount( + [NotNullWhen(true)] out MonetaryUsageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryUsageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryAmountDiscount(out var value)) { + /// // `value` is of type `MonetaryAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryAmountDiscount( + [NotNullWhen(true)] out MonetaryAmountDiscountAdjustment? value + ) + { + value = this.Value as MonetaryAmountDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryPercentageDiscount(out var value)) { + /// // `value` is of type `MonetaryPercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryPercentageDiscount( + [NotNullWhen(true)] out MonetaryPercentageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryPercentageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMinimum(out var value)) { + /// // `value` is of type `MonetaryMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMinimum([NotNullWhen(true)] out MonetaryMinimumAdjustment? value) + { + value = this.Value as MonetaryMinimumAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMaximum(out var value)) { + /// // `value` is of type `MonetaryMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMaximum([NotNullWhen(true)] out MonetaryMaximumAdjustment? value) + { + value = this.Value as MonetaryMaximumAdjustment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action monetaryUsageDiscount, + System::Action monetaryAmountDiscount, + System::Action monetaryPercentageDiscount, + System::Action monetaryMinimum, + System::Action monetaryMaximum + ) + { + switch (this.Value) + { + case MonetaryUsageDiscountAdjustment value: + monetaryUsageDiscount(value); + break; + case MonetaryAmountDiscountAdjustment value: + monetaryAmountDiscount(value); + break; + case MonetaryPercentageDiscountAdjustment value: + monetaryPercentageDiscount(value); + break; + case MonetaryMinimumAdjustment value: + monetaryMinimum(value); + break; + case MonetaryMaximumAdjustment value: + monetaryMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LineItemAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func monetaryUsageDiscount, + System::Func monetaryAmountDiscount, + System::Func monetaryPercentageDiscount, + System::Func monetaryMinimum, + System::Func monetaryMaximum + ) + { + return this.Value switch + { + MonetaryUsageDiscountAdjustment value => monetaryUsageDiscount(value), + MonetaryAmountDiscountAdjustment value => monetaryAmountDiscount(value), + MonetaryPercentageDiscountAdjustment value => monetaryPercentageDiscount(value), + MonetaryMinimumAdjustment value => monetaryMinimum(value), + MonetaryMaximumAdjustment value => monetaryMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LineItemAdjustment" + ), + }; + } + + public static implicit operator LineItemAdjustment(MonetaryUsageDiscountAdjustment value) => + new(value); + + public static implicit operator LineItemAdjustment(MonetaryAmountDiscountAdjustment value) => + new(value); + + public static implicit operator LineItemAdjustment( + MonetaryPercentageDiscountAdjustment value + ) => new(value); + + public static implicit operator LineItemAdjustment(MonetaryMinimumAdjustment value) => + new(value); + + public static implicit operator LineItemAdjustment(MonetaryMaximumAdjustment value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LineItemAdjustment" + ); + } + this.Switch( + (monetaryUsageDiscount) => monetaryUsageDiscount.Validate(), + (monetaryAmountDiscount) => monetaryAmountDiscount.Validate(), + (monetaryPercentageDiscount) => monetaryPercentageDiscount.Validate(), + (monetaryMinimum) => monetaryMinimum.Validate(), + (monetaryMaximum) => monetaryMaximum.Validate() + ); + } + + public virtual bool Equals(LineItemAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LineItemAdjustmentConverter : JsonConverter +{ + public override LineItemAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new LineItemAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + LineItemAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(SubLineItemConverter))] +public record class SubLineItem +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Amount + { + get + { + return Match(matrix: (x) => x.Amount, tier: (x) => x.Amount, other: (x) => x.Amount); + } + } + + public SubLineItemGrouping? Grouping + { + get + { + return Match( + matrix: (x) => x.Grouping, + tier: (x) => x.Grouping, + other: (x) => x.Grouping + ); + } + } + + public string Name + { + get { return Match(matrix: (x) => x.Name, tier: (x) => x.Name, other: (x) => x.Name); } + } + + public double Quantity + { + get + { + return Match( + matrix: (x) => x.Quantity, + tier: (x) => x.Quantity, + other: (x) => x.Quantity + ); + } + } + + public SubLineItem(MatrixSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(TierSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(OtherSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrix(out var value)) { + /// // `value` is of type `MatrixSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrix([NotNullWhen(true)] out MatrixSubLineItem? value) + { + value = this.Value as MatrixSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTier(out var value)) { + /// // `value` is of type `TierSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTier([NotNullWhen(true)] out TierSubLineItem? value) + { + value = this.Value as TierSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickOther(out var value)) { + /// // `value` is of type `OtherSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickOther([NotNullWhen(true)] out OtherSubLineItem? value) + { + value = this.Value as OtherSubLineItem; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action matrix, + System::Action tier, + System::Action other + ) + { + switch (this.Value) + { + case MatrixSubLineItem value: + matrix(value); + break; + case TierSubLineItem value: + tier(value); + break; + case OtherSubLineItem value: + other(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func matrix, + System::Func tier, + System::Func other + ) + { + return this.Value switch + { + MatrixSubLineItem value => matrix(value), + TierSubLineItem value => tier(value), + OtherSubLineItem value => other(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"), + }; + } + + public static implicit operator SubLineItem(MatrixSubLineItem value) => new(value); + + public static implicit operator SubLineItem(TierSubLineItem value) => new(value); + + public static implicit operator SubLineItem(OtherSubLineItem value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"); + } + this.Switch( + (matrix) => matrix.Validate(), + (tier) => tier.Validate(), + (other) => other.Validate() + ); + } + + public virtual bool Equals(SubLineItem? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubLineItemConverter : JsonConverter +{ + public override SubLineItem? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? type; + try + { + type = element.GetProperty("type").GetString(); + } + catch + { + type = null; + } + + switch (type) + { + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tier": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "'null'": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubLineItem(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubLineItem value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PaymentAttempt : JsonModel +{ + /// + /// The ID of the payment attempt. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The amount of the payment attempt. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The time at which the payment attempt was created. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + /// + /// The payment provider that attempted to collect the payment. + /// + public required ApiEnum? PaymentProvider + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "payment_provider" + ); + } + init { JsonModel.Set(this._rawData, "payment_provider", value); } + } + + /// + /// The ID of the payment attempt in the payment provider. + /// + public required string? PaymentProviderID + { + get { return JsonModel.GetNullableClass(this.RawData, "payment_provider_id"); } + init { JsonModel.Set(this._rawData, "payment_provider_id", value); } + } + + /// + /// URL to the downloadable PDF version of the receipt. This field will be `null` + /// for payment attempts that did not succeed. + /// + public required string? ReceiptPdf + { + get { return JsonModel.GetNullableClass(this.RawData, "receipt_pdf"); } + init { JsonModel.Set(this._rawData, "receipt_pdf", value); } + } + + /// + /// Whether the payment attempt succeeded. + /// + public required bool Succeeded + { + get { return JsonModel.GetNotNullStruct(this.RawData, "succeeded"); } + init { JsonModel.Set(this._rawData, "succeeded", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Amount; + _ = this.CreatedAt; + this.PaymentProvider?.Validate(); + _ = this.PaymentProviderID; + _ = this.ReceiptPdf; + _ = this.Succeeded; + } + + public PaymentAttempt() { } + + public PaymentAttempt(PaymentAttempt paymentAttempt) + : base(paymentAttempt) { } + + public PaymentAttempt(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PaymentAttempt(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PaymentAttempt FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PaymentAttemptFromRaw : IFromRawJson +{ + /// + public PaymentAttempt FromRawUnchecked(IReadOnlyDictionary rawData) => + PaymentAttempt.FromRawUnchecked(rawData); +} + +/// +/// The payment provider that attempted to collect the payment. +/// +[JsonConverter(typeof(PaymentProviderConverter))] +public enum PaymentProvider +{ + Stripe, +} + +sealed class PaymentProviderConverter : JsonConverter +{ + public override PaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => PaymentProvider.Stripe, + _ => (PaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PaymentProvider.Stripe => "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(StatusConverter))] +public enum Status +{ + Issued, + Paid, + Synced, + Void, + Draft, +} + +sealed class StatusConverter : JsonConverter +{ + public override Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "issued" => Status.Issued, + "paid" => Status.Paid, + "synced" => Status.Synced, + "void" => Status.Void, + "draft" => Status.Draft, + _ => (Status)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Status value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Status.Issued => "issued", + Status.Paid => "paid", + Status.Synced => "synced", + Status.Void => "void", + Status.Draft => "draft", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/ConversionRateTier.cs b/src/Orb/Models/ConversionRateTier.cs index 917a21fd..ba6b362f 100644 --- a/src/Orb/Models/ConversionRateTier.cs +++ b/src/Orb/Models/ConversionRateTier.cs @@ -1,31 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ConversionRateTier : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ConversionRateTier : JsonModel { /// /// Exclusive tier starting value /// public required double FirstUnit { - get - { - if (!this.Properties.TryGetValue("first_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "first_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["first_unit"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "first_unit"); } + init { JsonModel.Set(this._rawData, "first_unit", value); } } /// @@ -33,18 +24,8 @@ public required double FirstUnit /// public required string UnitAmount { - get - { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); - } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } } /// @@ -52,16 +33,11 @@ public required string UnitAmount /// public double? LastUnit { - get - { - if (!this.Properties.TryGetValue("last_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["last_unit"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "last_unit"); } + init { JsonModel.Set(this._rawData, "last_unit", value); } } + /// public override void Validate() { _ = this.FirstUnit; @@ -71,18 +47,34 @@ public override void Validate() public ConversionRateTier() { } + public ConversionRateTier(ConversionRateTier conversionRateTier) + : base(conversionRateTier) { } + + public ConversionRateTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ConversionRateTier(Generic::Dictionary properties) + [SetsRequiredMembers] + ConversionRateTier(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static ConversionRateTier FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class ConversionRateTierFromRaw : IFromRawJson +{ + /// + public ConversionRateTier FromRawUnchecked(IReadOnlyDictionary rawData) => + ConversionRateTier.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/ConversionRateTieredConfig.cs b/src/Orb/Models/ConversionRateTieredConfig.cs index aabcfebe..44def154 100644 --- a/src/Orb/Models/ConversionRateTieredConfig.cs +++ b/src/Orb/Models/ConversionRateTieredConfig.cs @@ -1,33 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ConversionRateTieredConfig - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ConversionRateTieredConfig : JsonModel { /// /// Tiers for rating based on total usage quantities into the specified tier /// - public required Generic::List Tiers + public required IReadOnlyList Tiers { - get - { - if (!this.Properties.TryGetValue("tiers", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("tiers", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tiers"); - } - set { this.Properties["tiers"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "tiers"); } + init { JsonModel.Set(this._rawData, "tiers", value); } } + /// public override void Validate() { foreach (var item in this.Tiers) @@ -38,18 +32,42 @@ public override void Validate() public ConversionRateTieredConfig() { } + public ConversionRateTieredConfig(ConversionRateTieredConfig conversionRateTieredConfig) + : base(conversionRateTieredConfig) { } + + public ConversionRateTieredConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ConversionRateTieredConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + ConversionRateTieredConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static ConversionRateTieredConfig FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public ConversionRateTieredConfig(List tiers) + : this() + { + this.Tiers = tiers; + } +} + +class ConversionRateTieredConfigFromRaw : IFromRawJson +{ + /// + public ConversionRateTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ConversionRateTieredConfig.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/ConversionRateUnitConfig.cs b/src/Orb/Models/ConversionRateUnitConfig.cs index a6ca5803..857c0688 100644 --- a/src/Orb/Models/ConversionRateUnitConfig.cs +++ b/src/Orb/Models/ConversionRateUnitConfig.cs @@ -1,36 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ConversionRateUnitConfig - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ConversionRateUnitConfig : JsonModel { /// /// Amount per unit of overage /// public required string UnitAmount { - get - { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); - } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } } + /// public override void Validate() { _ = this.UnitAmount; @@ -38,18 +29,42 @@ public override void Validate() public ConversionRateUnitConfig() { } + public ConversionRateUnitConfig(ConversionRateUnitConfig conversionRateUnitConfig) + : base(conversionRateUnitConfig) { } + + public ConversionRateUnitConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ConversionRateUnitConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + ConversionRateUnitConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static ConversionRateUnitConfig FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ConversionRateUnitConfig(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; } } + +class ConversionRateUnitConfigFromRaw : IFromRawJson +{ + /// + public ConversionRateUnitConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ConversionRateUnitConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/CouponRedemption.cs b/src/Orb/Models/CouponRedemption.cs index 29609225..a0050c38 100644 --- a/src/Orb/Models/CouponRedemption.cs +++ b/src/Orb/Models/CouponRedemption.cs @@ -1,61 +1,35 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CouponRedemption : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CouponRedemption : JsonModel { public required string CouponID { - get - { - if (!this.Properties.TryGetValue("coupon_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "coupon_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("coupon_id"); - } - set { this.Properties["coupon_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "coupon_id"); } + init { JsonModel.Set(this._rawData, "coupon_id", value); } } - public required System::DateTime? EndDate + public required DateTimeOffset? EndDate { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } } - public required System::DateTime StartDate + public required DateTimeOffset StartDate { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { _ = this.CouponID; @@ -65,18 +39,34 @@ public override void Validate() public CouponRedemption() { } + public CouponRedemption(CouponRedemption couponRedemption) + : base(couponRedemption) { } + + public CouponRedemption(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CouponRedemption(Generic::Dictionary properties) + [SetsRequiredMembers] + CouponRedemption(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CouponRedemption FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CouponRedemptionFromRaw : IFromRawJson +{ + /// + public CouponRedemption FromRawUnchecked(IReadOnlyDictionary rawData) => + CouponRedemption.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Coupons/Coupon.cs b/src/Orb/Models/Coupons/Coupon.cs index 2ccca081..a2c0543d 100644 --- a/src/Orb/Models/Coupons/Coupon.cs +++ b/src/Orb/Models/Coupons/Coupon.cs @@ -1,9 +1,10 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CouponProperties = Orb.Models.Coupons.CouponProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Coupons; @@ -12,61 +13,37 @@ namespace Orb.Models.Coupons; /// A coupon represents a reusable discount configuration that can be applied either /// as a fixed or percentage amount to an invoice or subscription. Coupons are activated /// using a redemption code, which applies the discount to a subscription or invoice. -/// The duration of a coupon determines how long it remains available for use by -/// end users. +/// The duration of a coupon determines how long it remains available for use by end users. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Coupon : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Coupon : JsonModel { /// /// Also referred to as coupon_id in this documentation. /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// An archived coupon can no longer be redeemed. Active coupons will have a value /// of null for `archived_at`; this field will be non-null for archived coupons. /// - public required System::DateTime? ArchivedAt + public required System::DateTimeOffset? ArchivedAt { get { - if (!this.Properties.TryGetValue("archived_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "archived_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "archived_at"); } - set { this.Properties["archived_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "archived_at", value); } } - public required CouponProperties::Discount Discount + public required CouponDiscount Discount { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount"); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } } /// @@ -75,20 +52,8 @@ public required string ID /// public required long? DurationInMonths { - get - { - if (!this.Properties.TryGetValue("duration_in_months", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration_in_months", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["duration_in_months"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "duration_in_months"); } + init { JsonModel.Set(this._rawData, "duration_in_months", value); } } /// @@ -97,17 +62,8 @@ public required long? DurationInMonths /// public required long? MaxRedemptions { - get - { - if (!this.Properties.TryGetValue("max_redemptions", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "max_redemptions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["max_redemptions"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "max_redemptions"); } + init { JsonModel.Set(this._rawData, "max_redemptions", value); } } /// @@ -115,18 +71,8 @@ public required long? MaxRedemptions /// public required string RedemptionCode { - get - { - if (!this.Properties.TryGetValue("redemption_code", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "redemption_code", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("redemption_code"); - } - set { this.Properties["redemption_code"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "redemption_code"); } + init { JsonModel.Set(this._rawData, "redemption_code", value); } } /// @@ -134,19 +80,11 @@ public required string RedemptionCode /// public required long TimesRedeemed { - get - { - if (!this.Properties.TryGetValue("times_redeemed", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "times_redeemed", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["times_redeemed"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "times_redeemed"); } + init { JsonModel.Set(this._rawData, "times_redeemed", value); } } + /// public override void Validate() { _ = this.ID; @@ -160,16 +98,297 @@ public override void Validate() public Coupon() { } + public Coupon(Coupon coupon) + : base(coupon) { } + + public Coupon(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Coupon(Generic::Dictionary properties) + [SetsRequiredMembers] + Coupon(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Coupon FromRawUnchecked(Generic::Dictionary properties) + /// + public static Coupon FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CouponFromRaw : IFromRawJson +{ + /// + public Coupon FromRawUnchecked(IReadOnlyDictionary rawData) => + Coupon.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CouponDiscountConverter))] +public record class CouponDiscount +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Reason + { + get { return Match(percentage: (x) => x.Reason, amount: (x) => x.Reason); } + } + + public CouponDiscount(PercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public CouponDiscount(AmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public CouponDiscount(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `PercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out PercentageDiscount? value) + { + value = this.Value as PercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `AmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out AmountDiscount? value) + { + value = this.Value as AmountDiscount; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (PercentageDiscount value) => {...}, + /// (AmountDiscount value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action percentage, + System::Action amount + ) + { + switch (this.Value) + { + case PercentageDiscount value: + percentage(value); + break; + case AmountDiscount value: + amount(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CouponDiscount" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (PercentageDiscount value) => {...}, + /// (AmountDiscount value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func percentage, + System::Func amount + ) + { + return this.Value switch + { + PercentageDiscount value => percentage(value), + AmountDiscount value => amount(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CouponDiscount" + ), + }; + } + + public static implicit operator CouponDiscount(PercentageDiscount value) => new(value); + + public static implicit operator CouponDiscount(AmountDiscount value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of CouponDiscount"); + } + this.Switch((percentage) => percentage.Validate(), (amount) => amount.Validate()); + } + + public virtual bool Equals(CouponDiscount? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CouponDiscountConverter : JsonConverter +{ + public override CouponDiscount? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); + } + catch + { + discountType = null; + } + + switch (discountType) + { + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new CouponDiscount(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + CouponDiscount value, + JsonSerializerOptions options + ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Coupons/CouponArchiveParams.cs b/src/Orb/Models/Coupons/CouponArchiveParams.cs index 27ff7724..6a568049 100644 --- a/src/Orb/Models/Coupons/CouponArchiveParams.cs +++ b/src/Orb/Models/Coupons/CouponArchiveParams.cs @@ -1,35 +1,77 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Coupons; /// -/// This endpoint allows a coupon to be archived. Archived coupons can no longer -/// be redeemed, and will be hidden from lists of active coupons. Additionally, once +/// This endpoint allows a coupon to be archived. Archived coupons can no longer be +/// redeemed, and will be hidden from lists of active coupons. Additionally, once /// a coupon is archived, its redemption code can be reused for a different coupon. /// -public sealed record class CouponArchiveParams : Orb::ParamsBase +public sealed record class CouponArchiveParams : ParamsBase { - public required string CouponID; + public string? CouponID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CouponArchiveParams() { } + + public CouponArchiveParams(CouponArchiveParams couponArchiveParams) + : base(couponArchiveParams) { } + + public CouponArchiveParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CouponArchiveParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CouponArchiveParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/coupons/{0}/archive", this.CouponID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Coupons/CouponCreateParams.cs b/src/Orb/Models/Coupons/CouponCreateParams.cs index ec35c3ab..9ca49f10 100644 --- a/src/Orb/Models/Coupons/CouponCreateParams.cs +++ b/src/Orb/Models/Coupons/CouponCreateParams.cs @@ -1,10 +1,13 @@ -using CouponCreateParamsProperties = Orb.Models.Coupons.CouponCreateParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Coupons; @@ -12,24 +15,24 @@ namespace Orb.Models.Coupons; /// This endpoint allows the creation of coupons, which can then be redeemed at subscription /// creation or plan change. /// -public sealed record class CouponCreateParams : Orb::ParamsBase +public sealed record class CouponCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required CouponCreateParamsProperties::Discount Discount + public required global::Orb.Models.Coupons.Discount Discount { get { - if (!this.BodyProperties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount"); + return JsonModel.GetNotNullClass( + this.RawBodyData, + "discount" + ); } - set { this.BodyProperties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "discount", value); } } /// @@ -37,21 +40,8 @@ public sealed record class CouponCreateParams : Orb::ParamsBase /// public required string RedemptionCode { - get - { - if (!this.BodyProperties.TryGetValue("redemption_code", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "redemption_code", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("redemption_code"); - } - set - { - this.BodyProperties["redemption_code"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "redemption_code"); } + init { JsonModel.Set(this._rawBodyData, "redemption_code", value); } } /// @@ -60,68 +50,491 @@ public required string RedemptionCode /// public long? DurationInMonths { - get + get { return JsonModel.GetNullableStruct(this.RawBodyData, "duration_in_months"); } + init { JsonModel.Set(this._rawBodyData, "duration_in_months", value); } + } + + /// + /// The maximum number of redemptions allowed for this coupon before it is exhausted;`null` + /// here means "unlimited". + /// + public long? MaxRedemptions + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "max_redemptions"); } + init { JsonModel.Set(this._rawBodyData, "max_redemptions", value); } + } + + public CouponCreateParams() { } + + public CouponCreateParams(CouponCreateParams couponCreateParams) + : base(couponCreateParams) + { + this._rawBodyData = [.. couponCreateParams._rawBodyData]; + } + + public CouponCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CouponCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static CouponCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/coupons") { - if ( - !this.BodyProperties.TryGetValue( - "duration_in_months", - out Json::JsonElement element - ) - ) - return null; + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } - return Json::JsonSerializer.Deserialize(element); + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } - set + } +} + +[JsonConverter(typeof(DiscountConverter))] +public record class Discount +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public JsonElement DiscountType + { + get { return Match(percentage: (x) => x.DiscountType, amount: (x) => x.DiscountType); } + } + + public Discount(Percentage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Discount(Amount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Discount(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `Percentage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out Percentage? value) + { + value = this.Value as Percentage; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `Amount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out Amount? value) + { + value = this.Value as Amount; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (Percentage value) => {...}, + /// (Amount value) => {...} + /// ); + /// + /// + /// + public void Switch(System::Action percentage, System::Action amount) + { + switch (this.Value) { - this.BodyProperties["duration_in_months"] = Json::JsonSerializer.SerializeToElement( - value - ); + case Percentage value: + percentage(value); + break; + case Amount value: + amount(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Discount"); } } /// - /// The maximum number of redemptions allowed for this coupon before it is exhausted;`null` - /// here means "unlimited". + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (Percentage value) => {...}, + /// (Amount value) => {...} + /// ); + /// + /// /// - public long? MaxRedemptions + public T Match(System::Func percentage, System::Func amount) { - get + return this.Value switch + { + Percentage value => percentage(value), + Amount value => amount(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Discount"), + }; + } + + public static implicit operator global::Orb.Models.Coupons.Discount(Percentage value) => + new(value); + + public static implicit operator global::Orb.Models.Coupons.Discount(Amount value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) { - if (!this.BodyProperties.TryGetValue("max_redemptions", out Json::JsonElement element)) - return null; + throw new OrbInvalidDataException("Data did not match any variant of Discount"); + } + this.Switch((percentage) => percentage.Validate(), (amount) => amount.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Coupons.Discount? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } - return Json::JsonSerializer.Deserialize(element); + public override int GetHashCode() + { + return 0; + } +} + +sealed class DiscountConverter : JsonConverter +{ + public override global::Orb.Models.Coupons.Discount? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); } - set + catch { - this.BodyProperties["max_redemptions"] = Json::JsonSerializer.SerializeToElement(value); + discountType = null; } + + switch (discountType) + { + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Coupons.Discount(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Coupons.Discount value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); } +} - public override System::Uri Url(Orb::IOrbClient client) +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Percentage : JsonModel +{ + public JsonElement DiscountType { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/coupons") + get { return JsonModel.GetNotNullStruct(this.RawData, "discount_type"); } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + public required double PercentageDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } + } + + /// + public override void Validate() + { + if ( + !JsonElement.DeepEquals( + this.DiscountType, + JsonSerializer.Deserialize("\"percentage\"") + ) + ) { - Query = this.QueryString(client), - }.Uri; + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.PercentageDiscount; } - public Http::StringContent BodyContent() + public Percentage() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this.DiscountType = JsonSerializer.Deserialize("\"percentage\""); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public Percentage(Percentage percentage) + : base(percentage) { } + + public Percentage(IReadOnlyDictionary rawData) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + this._rawData = [.. rawData]; + + this.DiscountType = JsonSerializer.Deserialize("\"percentage\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percentage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Percentage FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Percentage(double percentageDiscount) + : this() + { + this.PercentageDiscount = percentageDiscount; + } +} + +class PercentageFromRaw : IFromRawJson +{ + /// + public Percentage FromRawUnchecked(IReadOnlyDictionary rawData) => + Percentage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Amount : JsonModel +{ + public required string AmountDiscount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } + } + + public JsonElement DiscountType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "discount_type"); } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + /// + public override void Validate() + { + _ = this.AmountDiscount; + if ( + !JsonElement.DeepEquals( + this.DiscountType, + JsonSerializer.Deserialize("\"amount\"") + ) + ) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + throw new OrbInvalidDataException("Invalid value given for constant"); } } + + public Amount() + { + this.DiscountType = JsonSerializer.Deserialize("\"amount\""); + } + + public Amount(Amount amount) + : base(amount) { } + + public Amount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.DiscountType = JsonSerializer.Deserialize("\"amount\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Amount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Amount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Amount(string amountDiscount) + : this() + { + this.AmountDiscount = amountDiscount; + } +} + +class AmountFromRaw : IFromRawJson +{ + /// + public Amount FromRawUnchecked(IReadOnlyDictionary rawData) => + Amount.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Coupons/CouponCreateParamsProperties/Discount.cs b/src/Orb/Models/Coupons/CouponCreateParamsProperties/Discount.cs deleted file mode 100644 index c0b8fc77..00000000 --- a/src/Orb/Models/Coupons/CouponCreateParamsProperties/Discount.cs +++ /dev/null @@ -1,19 +0,0 @@ -using DiscountProperties = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties; -using DiscountVariants = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Coupons.CouponCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Discount -{ - internal Discount() { } - - public static DiscountVariants::Percentage Create(DiscountProperties::Percentage value) => - new(value); - - public static DiscountVariants::Amount Create(DiscountProperties::Amount value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/Amount.cs b/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/Amount.cs deleted file mode 100644 index 60e4c6ce..00000000 --- a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/Amount.cs +++ /dev/null @@ -1,66 +0,0 @@ -using AmountProperties = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties.AmountProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Amount : Orb::ModelBase, Orb::IFromRaw -{ - public required string AmountDiscount - { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_discount"); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required AmountProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AmountDiscount; - this.DiscountType.Validate(); - } - - public Amount() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Amount(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Amount FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/AmountProperties/DiscountType.cs b/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/AmountProperties/DiscountType.cs deleted file mode 100644 index 29c8d648..00000000 --- a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/AmountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties.AmountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Amount = new("amount"); - - readonly string _value = value; - - public enum Value - { - Amount, - } - - public Value Known() => - _value switch - { - "amount" => Value.Amount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/Percentage.cs b/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/Percentage.cs deleted file mode 100644 index db105616..00000000 --- a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/Percentage.cs +++ /dev/null @@ -1,70 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PercentageProperties = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties.PercentageProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Percentage : Orb::ModelBase, Orb::IFromRaw -{ - public required PercentageProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double PercentageDiscount - { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.DiscountType.Validate(); - _ = this.PercentageDiscount; - } - - public Percentage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Percentage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Percentage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/PercentageProperties/DiscountType.cs b/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/PercentageProperties/DiscountType.cs deleted file mode 100644 index fd1a73b2..00000000 --- a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountProperties/PercentageProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties.PercentageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - readonly string _value = value; - - public enum Value - { - Percentage, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountVariants/All.cs b/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountVariants/All.cs deleted file mode 100644 index 161bf4c0..00000000 --- a/src/Orb/Models/Coupons/CouponCreateParamsProperties/DiscountVariants/All.cs +++ /dev/null @@ -1,40 +0,0 @@ -using CouponCreateParamsProperties = Orb.Models.Coupons.CouponCreateParamsProperties; -using DiscountProperties = Orb.Models.Coupons.CouponCreateParamsProperties.DiscountProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Coupons.CouponCreateParamsProperties.DiscountVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class Percentage(DiscountProperties::Percentage Value) - : CouponCreateParamsProperties::Discount, - Orb::IVariant -{ - public static Percentage From(DiscountProperties::Percentage value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Amount(DiscountProperties::Amount Value) - : CouponCreateParamsProperties::Discount, - Orb::IVariant -{ - public static Amount From(DiscountProperties::Amount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Coupons/CouponFetchParams.cs b/src/Orb/Models/Coupons/CouponFetchParams.cs index 590cd97e..2882856a 100644 --- a/src/Orb/Models/Coupons/CouponFetchParams.cs +++ b/src/Orb/Models/Coupons/CouponFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Coupons; @@ -8,26 +12,64 @@ namespace Orb.Models.Coupons; /// This endpoint retrieves a coupon by its ID. To fetch coupons by their redemption /// code, use the [List coupons](list-coupons) endpoint with the redemption_code parameter. /// -public sealed record class CouponFetchParams : Orb::ParamsBase +public sealed record class CouponFetchParams : ParamsBase { - public required string CouponID; + public string? CouponID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CouponFetchParams() { } + + public CouponFetchParams(CouponFetchParams couponFetchParams) + : base(couponFetchParams) { } + + public CouponFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CouponFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CouponFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/coupons/{0}", this.CouponID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/coupons/{0}", this.CouponID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Coupons/CouponListPage.cs b/src/Orb/Models/Coupons/CouponListPage.cs new file mode 100644 index 00000000..b3d8a5e7 --- /dev/null +++ b/src/Orb/Models/Coupons/CouponListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Coupons; + +public sealed class CouponListPage( + ICouponService service, + CouponListParams parameters, + CouponListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Coupons/CouponListPageResponse.cs b/src/Orb/Models/Coupons/CouponListPageResponse.cs index d03528f2..7bb79cce 100644 --- a/src/Orb/Models/Coupons/CouponListPageResponse.cs +++ b/src/Orb/Models/Coupons/CouponListPageResponse.cs @@ -1,50 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Coupons; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CouponListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CouponListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +40,35 @@ public override void Validate() public CouponListPageResponse() { } + public CouponListPageResponse(CouponListPageResponse couponListPageResponse) + : base(couponListPageResponse) { } + + public CouponListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CouponListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CouponListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CouponListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CouponListPageResponseFromRaw : IFromRawJson +{ + /// + public CouponListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CouponListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Coupons/CouponListParams.cs b/src/Orb/Models/Coupons/CouponListParams.cs index 58eb50e1..d4548705 100644 --- a/src/Orb/Models/Coupons/CouponListParams.cs +++ b/src/Orb/Models/Coupons/CouponListParams.cs @@ -1,19 +1,22 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Coupons; /// /// This endpoint returns a list of all coupons for an account in a list format. /// -/// The list of coupons is ordered starting from the most recently created coupon. -/// The response also includes `pagination_metadata`, which lets the caller retrieve -/// the next page of results if they exist. More information about pagination can -/// be found in the Pagination-metadata schema. +/// The list of coupons is ordered starting from the most recently created +/// coupon. The response also includes `pagination_metadata`, which lets the caller +/// retrieve the next page of results if they exist. More information about pagination +/// can be found in the Pagination-metadata schema. /// -public sealed record class CouponListParams : Orb::ParamsBase +public sealed record class CouponListParams : ParamsBase { /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -21,14 +24,8 @@ public sealed record class CouponListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -36,14 +33,16 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } /// @@ -51,19 +50,8 @@ public long? Limit /// public string? RedemptionCode { - get - { - if (!this.QueryProperties.TryGetValue("redemption_code", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["redemption_code"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "redemption_code"); } + init { JsonModel.Set(this._rawQueryData, "redemption_code", value); } } /// @@ -71,33 +59,62 @@ public string? RedemptionCode /// public bool? ShowArchived { - get - { - if (!this.QueryProperties.TryGetValue("show_archived", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableStruct(this.RawQueryData, "show_archived"); } + init { JsonModel.Set(this._rawQueryData, "show_archived", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["show_archived"] = Json::JsonSerializer.SerializeToElement(value); - } + public CouponListParams() { } + + public CouponListParams(CouponListParams couponListParams) + : base(couponListParams) { } + + public CouponListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CouponListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CouponListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/coupons") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/coupons") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Coupons/CouponProperties/Discount.cs b/src/Orb/Models/Coupons/CouponProperties/Discount.cs deleted file mode 100644 index 89cd34fa..00000000 --- a/src/Orb/Models/Coupons/CouponProperties/Discount.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DiscountVariants = Orb.Models.Coupons.CouponProperties.DiscountVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Coupons.CouponProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Discount -{ - internal Discount() { } - - public static DiscountVariants::PercentageDiscount Create(Models::PercentageDiscount value) => - new(value); - - public static DiscountVariants::AmountDiscount Create(Models::AmountDiscount value) => - new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Coupons/CouponProperties/DiscountVariants/All.cs b/src/Orb/Models/Coupons/CouponProperties/DiscountVariants/All.cs deleted file mode 100644 index ca6b8eef..00000000 --- a/src/Orb/Models/Coupons/CouponProperties/DiscountVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using CouponProperties = Orb.Models.Coupons.CouponProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Coupons.CouponProperties.DiscountVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PercentageDiscount(Models::PercentageDiscount Value) - : CouponProperties::Discount, - Orb::IVariant -{ - public static PercentageDiscount From(Models::PercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmountDiscount(Models::AmountDiscount Value) - : CouponProperties::Discount, - Orb::IVariant -{ - public static AmountDiscount From(Models::AmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Coupons/Subscriptions/SubscriptionListPage.cs b/src/Orb/Models/Coupons/Subscriptions/SubscriptionListPage.cs new file mode 100644 index 00000000..2f0dc7f7 --- /dev/null +++ b/src/Orb/Models/Coupons/Subscriptions/SubscriptionListPage.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Coupons; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Models.Coupons.Subscriptions; + +public sealed class SubscriptionListPage( + ISubscriptionService service, + SubscriptionListParams parameters, + Subscriptions::SubscriptionSubscriptions response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Coupons/Subscriptions/SubscriptionListParams.cs b/src/Orb/Models/Coupons/Subscriptions/SubscriptionListParams.cs index 0d75346c..d1decb70 100644 --- a/src/Orb/Models/Coupons/Subscriptions/SubscriptionListParams.cs +++ b/src/Orb/Models/Coupons/Subscriptions/SubscriptionListParams.cs @@ -1,19 +1,22 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Coupons.Subscriptions; /// -/// This endpoint returns a list of all subscriptions that have redeemed a given -/// coupon as a [paginated](/api-reference/pagination) list, ordered starting from -/// the most recently created subscription. For a full discussion of the subscription -/// resource, see [Subscription](/core-concepts#subscription). +/// This endpoint returns a list of all subscriptions that have redeemed a given coupon +/// as a [paginated](/api-reference/pagination) list, ordered starting from the most +/// recently created subscription. For a full discussion of the subscription resource, +/// see [Subscription](/core-concepts#subscription). /// -public sealed record class SubscriptionListParams : Orb::ParamsBase +public sealed record class SubscriptionListParams : ParamsBase { - public required string CouponID; + public string? CouponID { get; init; } /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -21,14 +24,8 @@ public sealed record class SubscriptionListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -36,33 +33,73 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionListParams() { } + + public SubscriptionListParams(SubscriptionListParams subscriptionListParams) + : base(subscriptionListParams) { } + + public SubscriptionListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/coupons/{0}/subscriptions", this.CouponID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/CreditNote.cs b/src/Orb/Models/CreditNote.cs deleted file mode 100644 index 2ba4c375..00000000 --- a/src/Orb/Models/CreditNote.cs +++ /dev/null @@ -1,360 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CreditNoteProperties = Orb.Models.CreditNoteProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -/// -/// The [Credit Note](/invoicing/credit-notes) resource represents a credit that has -/// been applied to a particular invoice. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditNote : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The Orb id of this credit note. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The creation time of the resource in Orb. - /// - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The unique identifier for credit notes. - /// - public required string CreditNoteNumber - { - get - { - if (!this.Properties.TryGetValue("credit_note_number", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_note_number"); - } - set - { - this.Properties["credit_note_number"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// A URL to a PDF of the credit note. - /// - public required string? CreditNotePdf - { - get - { - if (!this.Properties.TryGetValue("credit_note_pdf", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note_pdf", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["credit_note_pdf"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required CustomerMinified Customer - { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the invoice resource that this credit note is applied to. - /// - public required string InvoiceID - { - get - { - if (!this.Properties.TryGetValue("invoice_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_id"); - } - set { this.Properties["invoice_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// All of the line items associated with this credit note. - /// - public required Generic::List LineItems - { - get - { - if (!this.Properties.TryGetValue("line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("line_items"); - } - set { this.Properties["line_items"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The maximum amount applied on the original invoice - /// - public required CreditNoteProperties::MaximumAmountAdjustment? MaximumAmountAdjustment - { - get - { - if ( - !this.Properties.TryGetValue( - "maximum_amount_adjustment", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "maximum_amount_adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["maximum_amount_adjustment"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An optional memo supplied on the credit note. - /// - public required string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("memo", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Any credited amount from the applied minimum on the invoice. - /// - public required string? MinimumAmountRefunded - { - get - { - if ( - !this.Properties.TryGetValue( - "minimum_amount_refunded", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "minimum_amount_refunded", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["minimum_amount_refunded"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required CreditNoteProperties::Reason? Reason - { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The total prior to any creditable invoice-level discounts or minimums. - /// - public required string Subtotal - { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The total including creditable invoice-level discounts or minimums, and tax. - /// - public required string Total - { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required CreditNoteProperties::Type Type - { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The time at which the credit note was voided in Orb, if applicable. - /// - public required System::DateTime? VoidedAt - { - get - { - if (!this.Properties.TryGetValue("voided_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["voided_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Any discounts applied on the original invoice. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.CreatedAt; - _ = this.CreditNoteNumber; - _ = this.CreditNotePdf; - this.Customer.Validate(); - _ = this.InvoiceID; - foreach (var item in this.LineItems) - { - item.Validate(); - } - this.MaximumAmountAdjustment?.Validate(); - _ = this.Memo; - _ = this.MinimumAmountRefunded; - this.Reason?.Validate(); - _ = this.Subtotal; - _ = this.Total; - this.Type.Validate(); - _ = this.VoidedAt; - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - } - - public CreditNote() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditNote(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static CreditNote FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/Discount.cs b/src/Orb/Models/CreditNoteProperties/Discount.cs deleted file mode 100644 index f54f8808..00000000 --- a/src/Orb/Models/CreditNoteProperties/Discount.cs +++ /dev/null @@ -1,121 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DiscountProperties = Orb.Models.CreditNoteProperties.DiscountProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Discount : Orb::ModelBase, Orb::IFromRaw -{ - public required string AmountApplied - { - get - { - if (!this.Properties.TryGetValue("amount_applied", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_applied", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_applied"); - } - set { this.Properties["amount_applied"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DiscountProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double PercentageDiscount - { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Generic::List? AppliesToPrices - { - get - { - if (!this.Properties.TryGetValue("applies_to_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.Properties["applies_to_prices"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public string? Reason - { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AmountApplied; - this.DiscountType.Validate(); - _ = this.PercentageDiscount; - foreach (var item in this.AppliesToPrices ?? []) - { - item.Validate(); - } - _ = this.Reason; - } - - public Discount() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Discount(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Discount FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/DiscountProperties/AppliesToPrice.cs b/src/Orb/Models/CreditNoteProperties/DiscountProperties/AppliesToPrice.cs deleted file mode 100644 index 75f3ba22..00000000 --- a/src/Orb/Models/CreditNoteProperties/DiscountProperties/AppliesToPrice.cs +++ /dev/null @@ -1,61 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AppliesToPrice : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Name; - } - - public AppliesToPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AppliesToPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AppliesToPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/DiscountProperties/DiscountType.cs b/src/Orb/Models/CreditNoteProperties/DiscountProperties/DiscountType.cs deleted file mode 100644 index 21827570..00000000 --- a/src/Orb/Models/CreditNoteProperties/DiscountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - readonly string _value = value; - - public enum Value - { - Percentage, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/LineItem.cs b/src/Orb/Models/CreditNoteProperties/LineItem.cs deleted file mode 100644 index 0ed014db..00000000 --- a/src/Orb/Models/CreditNoteProperties/LineItem.cs +++ /dev/null @@ -1,232 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using LineItemProperties = Orb.Models.CreditNoteProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LineItem : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The Orb id of this resource. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The amount of the line item, including any line item minimums and discounts. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item associated with this line item. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the corresponding invoice line item. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional quantity credited. - /// - public required double? Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The amount of the line item, excluding any line item minimums and discounts. - /// - public required string Subtotal - { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Any tax amounts applied onto the line item. - /// - public required Generic::List TaxAmounts - { - get - { - if (!this.Properties.TryGetValue("tax_amounts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_amounts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tax_amounts"); - } - set { this.Properties["tax_amounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Any line item discounts from the invoice's line item. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end time of the service period for this credit note line item. - /// - public System::DateTime? EndTimeExclusive - { - get - { - if (!this.Properties.TryGetValue("end_time_exclusive", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["end_time_exclusive"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The start time of the service period for this credit note line item. - /// - public System::DateTime? StartTimeInclusive - { - get - { - if (!this.Properties.TryGetValue("start_time_inclusive", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["start_time_inclusive"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Amount; - _ = this.ItemID; - _ = this.Name; - _ = this.Quantity; - _ = this.Subtotal; - foreach (var item in this.TaxAmounts) - { - item.Validate(); - } - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - _ = this.EndTimeExclusive; - _ = this.StartTimeInclusive; - } - - public LineItem() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LineItem(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static LineItem FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/LineItemProperties/Discount.cs b/src/Orb/Models/CreditNoteProperties/LineItemProperties/Discount.cs deleted file mode 100644 index ae718e7f..00000000 --- a/src/Orb/Models/CreditNoteProperties/LineItemProperties/Discount.cs +++ /dev/null @@ -1,152 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DiscountProperties = Orb.Models.CreditNoteProperties.LineItemProperties.DiscountProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties.LineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Discount : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string AmountApplied - { - get - { - if (!this.Properties.TryGetValue("amount_applied", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_applied", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_applied"); - } - set { this.Properties["amount_applied"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::List AppliesToPriceIDs - { - get - { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required DiscountProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double PercentageDiscount - { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public string? AmountDiscount - { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public string? Reason - { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.AmountApplied; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } - this.DiscountType.Validate(); - _ = this.PercentageDiscount; - _ = this.AmountDiscount; - _ = this.Reason; - } - - public Discount() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Discount(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Discount FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/LineItemProperties/DiscountProperties/DiscountType.cs b/src/Orb/Models/CreditNoteProperties/LineItemProperties/DiscountProperties/DiscountType.cs deleted file mode 100644 index f45f295f..00000000 --- a/src/Orb/Models/CreditNoteProperties/LineItemProperties/DiscountProperties/DiscountType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties.LineItemProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - public static readonly DiscountType Amount = new("amount"); - - readonly string _value = value; - - public enum Value - { - Percentage, - Amount, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - "amount" => Value.Amount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustment.cs b/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustment.cs deleted file mode 100644 index 8d69e2f5..00000000 --- a/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustment.cs +++ /dev/null @@ -1,127 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MaximumAmountAdjustmentProperties = Orb.Models.CreditNoteProperties.MaximumAmountAdjustmentProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties; - -/// -/// The maximum amount applied on the original invoice -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MaximumAmountAdjustment - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string AmountApplied - { - get - { - if (!this.Properties.TryGetValue("amount_applied", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_applied", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_applied"); - } - set { this.Properties["amount_applied"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MaximumAmountAdjustmentProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double PercentageDiscount - { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Generic::List? AppliesToPrices - { - get - { - if (!this.Properties.TryGetValue("applies_to_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.Properties["applies_to_prices"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public string? Reason - { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AmountApplied; - this.DiscountType.Validate(); - _ = this.PercentageDiscount; - foreach (var item in this.AppliesToPrices ?? []) - { - item.Validate(); - } - _ = this.Reason; - } - - public MaximumAmountAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MaximumAmountAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static MaximumAmountAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustmentProperties/AppliesToPrice.cs b/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustmentProperties/AppliesToPrice.cs deleted file mode 100644 index f7ece7ce..00000000 --- a/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustmentProperties/AppliesToPrice.cs +++ /dev/null @@ -1,61 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties.MaximumAmountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AppliesToPrice : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Name; - } - - public AppliesToPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AppliesToPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AppliesToPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustmentProperties/DiscountType.cs b/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustmentProperties/DiscountType.cs deleted file mode 100644 index be6dc11e..00000000 --- a/src/Orb/Models/CreditNoteProperties/MaximumAmountAdjustmentProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties.MaximumAmountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - readonly string _value = value; - - public enum Value - { - Percentage, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/Reason.cs b/src/Orb/Models/CreditNoteProperties/Reason.cs deleted file mode 100644 index 2d7c7d3b..00000000 --- a/src/Orb/Models/CreditNoteProperties/Reason.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Reason(string value) : Orb::IEnum -{ - public static readonly Reason Duplicate = new("Duplicate"); - - public static readonly Reason Fraudulent = new("Fraudulent"); - - public static readonly Reason OrderChange = new("Order change"); - - public static readonly Reason ProductUnsatisfactory = new("Product unsatisfactory"); - - readonly string _value = value; - - public enum Value - { - Duplicate, - Fraudulent, - OrderChange, - ProductUnsatisfactory, - } - - public Value Known() => - _value switch - { - "Duplicate" => Value.Duplicate, - "Fraudulent" => Value.Fraudulent, - "Order change" => Value.OrderChange, - "Product unsatisfactory" => Value.ProductUnsatisfactory, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Reason FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CreditNoteProperties/Type.cs b/src/Orb/Models/CreditNoteProperties/Type.cs deleted file mode 100644 index db6c074e..00000000 --- a/src/Orb/Models/CreditNoteProperties/Type.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNoteProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Refund = new("refund"); - - public static readonly Type Adjustment = new("adjustment"); - - readonly string _value = value; - - public enum Value - { - Refund, - Adjustment, - } - - public Value Known() => - _value switch - { - "refund" => Value.Refund, - "adjustment" => Value.Adjustment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CreditNoteTiny.cs b/src/Orb/Models/CreditNoteTiny.cs index ce9be9bd..bcb94632 100644 --- a/src/Orb/Models/CreditNoteTiny.cs +++ b/src/Orb/Models/CreditNoteTiny.cs @@ -1,31 +1,25 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditNoteTiny : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CreditNoteTiny : JsonModel { /// /// The id of the Credit note /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } + /// public override void Validate() { _ = this.ID; @@ -33,18 +27,39 @@ public override void Validate() public CreditNoteTiny() { } + public CreditNoteTiny(CreditNoteTiny creditNoteTiny) + : base(creditNoteTiny) { } + + public CreditNoteTiny(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditNoteTiny(Generic::Dictionary properties) + [SetsRequiredMembers] + CreditNoteTiny(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static CreditNoteTiny FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static CreditNoteTiny FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CreditNoteTiny(string id) + : this() { - return new(properties); + this.ID = id; } } + +class CreditNoteTinyFromRaw : IFromRawJson +{ + /// + public CreditNoteTiny FromRawUnchecked(IReadOnlyDictionary rawData) => + CreditNoteTiny.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/CreditNotes/CreditNoteCreateParams.cs b/src/Orb/Models/CreditNotes/CreditNoteCreateParams.cs index 168903e7..ca3218eb 100644 --- a/src/Orb/Models/CreditNotes/CreditNoteCreateParams.cs +++ b/src/Orb/Models/CreditNotes/CreditNoteCreateParams.cs @@ -1,97 +1,88 @@ -using CreditNoteCreateParamsProperties = Orb.Models.CreditNotes.CreditNoteCreateParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.CreditNotes; /// /// This endpoint is used to create a single [`Credit Note`](/invoicing/credit-notes). /// -/// The credit note service period configuration supports two explicit modes: +/// The credit note service period configuration supports two explicit modes: /// -/// 1. Global service periods: Specify start_date and end_date at the credit note -/// level. These dates will be applied to all line items uniformly. +/// 1. Global service periods: Specify start_date and end_date at the credit +/// note level. These dates will be applied to all line items uniformly. /// -/// 2. Individual service periods: Specify start_date and end_date for each line -/// item. When using this mode, ALL line items must have individual periods specified. +/// 2. Individual service periods: Specify start_date and end_date for each +/// line item. When using this mode, ALL line items must have individual periods specified. /// -/// 3. Default behavior: If no service periods are specified (neither global nor individual), -/// the original invoice line item service periods will be used. +/// 3. Default behavior: If no service periods are specified (neither global +/// nor individual), the original invoice line item service periods will be used. /// -/// Note: Mixing global and individual service periods in the same request is not -/// allowed to prevent confusion. +/// Note: Mixing global and individual service periods in the same request is +/// not allowed to prevent confusion. /// -/// Service period dates are normalized to the start of the day in the customer's -/// timezone to ensure consistent handling across different timezones. +/// Service period dates are normalized to the start of the day in the customer's +/// timezone to ensure consistent handling across different timezones. /// -/// Date Format: Use start_date and end_date with format "YYYY-MM-DD" (e.g., "2023-09-22") -/// to match other Orb APIs like /v1/invoice_line_items. +/// Date Format: Use start_date and end_date with format "YYYY-MM-DD" (e.g., +/// "2023-09-22") to match other Orb APIs like /v1/invoice_line_items. /// -/// Note: Both start_date and end_date are inclusive - the service period will cover -/// both the start date and end date completely (from start of start_date to end -/// of end_date). +/// Note: Both start_date and end_date are inclusive - the service period will +/// cover both the start date and end date completely (from start of start_date to +/// end of end_date). /// -public sealed record class CreditNoteCreateParams : Orb::ParamsBase +public sealed record class CreditNoteCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required Generic::List LineItems + public required IReadOnlyList LineItems { get { - if (!this.BodyProperties.TryGetValue("line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("line_items"); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "line_items" + ); } - set { this.BodyProperties["line_items"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "line_items", value); } } /// /// An optional reason for the credit note. /// - public required CreditNoteCreateParamsProperties::Reason Reason + public required ApiEnum Reason { get { - if (!this.BodyProperties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("reason"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawBodyData, "reason"); } - set { this.BodyProperties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "reason", value); } } /// - /// A date string to specify the global credit note service period end date in the - /// customer's timezone. This will be applied to all line items that don't have - /// their own individual service periods specified. If not provided, line items - /// will use their original invoice line item service periods. This date is inclusive. + /// A date string to specify the global credit note service period end date in + /// the customer's timezone. This will be applied to all line items that don't + /// have their own individual service periods specified. If not provided, line + /// items will use their original invoice line item service periods. This date + /// is inclusive. /// - public System::DateOnly? EndDate + public string? EndDate { - get - { - if (!this.BodyProperties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "end_date"); } + init { JsonModel.Set(this._rawBodyData, "end_date", value); } } /// @@ -99,57 +90,242 @@ public sealed record class CreditNoteCreateParams : Orb::ParamsBase /// public string? Memo { - get - { - if (!this.BodyProperties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["memo"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "memo"); } + init { JsonModel.Set(this._rawBodyData, "memo", value); } } /// - /// A date string to specify the global credit note service period start date in - /// the customer's timezone. This will be applied to all line items that don't - /// have their own individual service periods specified. If not provided, line items - /// will use their original invoice line item service periods. This date is inclusive. + /// A date string to specify the global credit note service period start date + /// in the customer's timezone. This will be applied to all line items that don't + /// have their own individual service periods specified. If not provided, line + /// items will use their original invoice line item service periods. This date + /// is inclusive. /// - public System::DateOnly? StartDate + public string? StartDate { - get - { - if (!this.BodyProperties.TryGetValue("start_date", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "start_date"); } + init { JsonModel.Set(this._rawBodyData, "start_date", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + public CreditNoteCreateParams() { } + + public CreditNoteCreateParams(CreditNoteCreateParams creditNoteCreateParams) + : base(creditNoteCreateParams) + { + this._rawBodyData = [.. creditNoteCreateParams._rawBodyData]; + } + + public CreditNoteCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } - public override System::Uri Url(Orb::IOrbClient client) +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditNoteCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/credit_notes") + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static CreditNoteCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/credit_notes") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.CreditNotes.LineItem, + global::Orb.Models.CreditNotes.LineItemFromRaw + >) +)] +public sealed record class LineItem : JsonModel +{ + /// + /// The total amount in the invoice's currency to credit this line item. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the line item to credit. + /// + public required string InvoiceLineItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "invoice_line_item_id"); } + init { JsonModel.Set(this._rawData, "invoice_line_item_id", value); } + } + + /// + /// A date string to specify this line item's credit note service period end date + /// in the customer's timezone. If provided, this will be used for this specific + /// line item. If not provided, will use the global end_date if available, otherwise + /// defaults to the original invoice line item's end date. This date is inclusive. + /// + public string? EndDate + { + get { return JsonModel.GetNullableClass(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// A date string to specify this line item's credit note service period start + /// date in the customer's timezone. If provided, this will be used for this + /// specific line item. If not provided, will use the global start_date if available, + /// otherwise defaults to the original invoice line item's start date. This date + /// is inclusive. + /// + public string? StartDate + { + get { return JsonModel.GetNullableClass(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + _ = this.InvoiceLineItemID; + _ = this.EndDate; + _ = this.StartDate; + } + + public LineItem() { } + + public LineItem(global::Orb.Models.CreditNotes.LineItem lineItem) + : base(lineItem) { } + + public LineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.CreditNotes.LineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class LineItemFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.CreditNotes.LineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.CreditNotes.LineItem.FromRawUnchecked(rawData); +} + +/// +/// An optional reason for the credit note. +/// +[JsonConverter(typeof(global::Orb.Models.CreditNotes.ReasonConverter))] +public enum Reason +{ + Duplicate, + Fraudulent, + OrderChange, + ProductUnsatisfactory, +} + +sealed class ReasonConverter : JsonConverter +{ + public override global::Orb.Models.CreditNotes.Reason Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "duplicate" => global::Orb.Models.CreditNotes.Reason.Duplicate, + "fraudulent" => global::Orb.Models.CreditNotes.Reason.Fraudulent, + "order_change" => global::Orb.Models.CreditNotes.Reason.OrderChange, + "product_unsatisfactory" => global::Orb.Models.CreditNotes.Reason.ProductUnsatisfactory, + _ => (global::Orb.Models.CreditNotes.Reason)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.CreditNotes.Reason value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.CreditNotes.Reason.Duplicate => "duplicate", + global::Orb.Models.CreditNotes.Reason.Fraudulent => "fraudulent", + global::Orb.Models.CreditNotes.Reason.OrderChange => "order_change", + global::Orb.Models.CreditNotes.Reason.ProductUnsatisfactory => + "product_unsatisfactory", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/CreditNotes/CreditNoteCreateParamsProperties/LineItem.cs b/src/Orb/Models/CreditNotes/CreditNoteCreateParamsProperties/LineItem.cs deleted file mode 100644 index e49e443a..00000000 --- a/src/Orb/Models/CreditNotes/CreditNoteCreateParamsProperties/LineItem.cs +++ /dev/null @@ -1,116 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNotes.CreditNoteCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LineItem : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The total amount in the invoice's currency to credit this line item. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the line item to credit. - /// - public required string InvoiceLineItemID - { - get - { - if (!this.Properties.TryGetValue("invoice_line_item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_line_item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_line_item_id"); - } - set - { - this.Properties["invoice_line_item_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// A date string to specify this line item's credit note service period end date - /// in the customer's timezone. If provided, this will be used for this specific - /// line item. If not provided, will use the global end_date if available, otherwise - /// defaults to the original invoice line item's end date. This date is inclusive. - /// - public System::DateOnly? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A date string to specify this line item's credit note service period start - /// date in the customer's timezone. If provided, this will be used for this specific - /// line item. If not provided, will use the global start_date if available, otherwise - /// defaults to the original invoice line item's start date. This date is inclusive. - /// - public System::DateOnly? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - _ = this.InvoiceLineItemID; - _ = this.EndDate; - _ = this.StartDate; - } - - public LineItem() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LineItem(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static LineItem FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/CreditNotes/CreditNoteCreateParamsProperties/Reason.cs b/src/Orb/Models/CreditNotes/CreditNoteCreateParamsProperties/Reason.cs deleted file mode 100644 index 9fdce5ad..00000000 --- a/src/Orb/Models/CreditNotes/CreditNoteCreateParamsProperties/Reason.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CreditNotes.CreditNoteCreateParamsProperties; - -/// -/// An optional reason for the credit note. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Reason(string value) : Orb::IEnum -{ - public static readonly Reason Duplicate = new("duplicate"); - - public static readonly Reason Fraudulent = new("fraudulent"); - - public static readonly Reason OrderChange = new("order_change"); - - public static readonly Reason ProductUnsatisfactory = new("product_unsatisfactory"); - - readonly string _value = value; - - public enum Value - { - Duplicate, - Fraudulent, - OrderChange, - ProductUnsatisfactory, - } - - public Value Known() => - _value switch - { - "duplicate" => Value.Duplicate, - "fraudulent" => Value.Fraudulent, - "order_change" => Value.OrderChange, - "product_unsatisfactory" => Value.ProductUnsatisfactory, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Reason FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CreditNotes/CreditNoteFetchParams.cs b/src/Orb/Models/CreditNotes/CreditNoteFetchParams.cs index 084a40b8..b2c92a7f 100644 --- a/src/Orb/Models/CreditNotes/CreditNoteFetchParams.cs +++ b/src/Orb/Models/CreditNotes/CreditNoteFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.CreditNotes; @@ -8,27 +12,65 @@ namespace Orb.Models.CreditNotes; /// This endpoint is used to fetch a single [`Credit Note`](/invoicing/credit-notes) /// given an identifier. /// -public sealed record class CreditNoteFetchParams : Orb::ParamsBase +public sealed record class CreditNoteFetchParams : ParamsBase { - public required string CreditNoteID; + public string? CreditNoteID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CreditNoteFetchParams() { } + + public CreditNoteFetchParams(CreditNoteFetchParams creditNoteFetchParams) + : base(creditNoteFetchParams) { } + + public CreditNoteFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditNoteFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CreditNoteFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/credit_notes/{0}", this.CreditNoteID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/CreditNotes/CreditNoteListPage.cs b/src/Orb/Models/CreditNotes/CreditNoteListPage.cs new file mode 100644 index 00000000..60ed3ecf --- /dev/null +++ b/src/Orb/Models/CreditNotes/CreditNoteListPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.CreditNotes; + +public sealed class CreditNoteListPage( + ICreditNoteService service, + CreditNoteListParams parameters, + CreditNoteListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/CreditNotes/CreditNoteListPageResponse.cs b/src/Orb/Models/CreditNotes/CreditNoteListPageResponse.cs index 3cabe13c..43605cc9 100644 --- a/src/Orb/Models/CreditNotes/CreditNoteListPageResponse.cs +++ b/src/Orb/Models/CreditNotes/CreditNoteListPageResponse.cs @@ -1,50 +1,36 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.CreditNotes; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditNoteListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CreditNoteListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +42,35 @@ public override void Validate() public CreditNoteListPageResponse() { } + public CreditNoteListPageResponse(CreditNoteListPageResponse creditNoteListPageResponse) + : base(creditNoteListPageResponse) { } + + public CreditNoteListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditNoteListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CreditNoteListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CreditNoteListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CreditNoteListPageResponseFromRaw : IFromRawJson +{ + /// + public CreditNoteListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CreditNoteListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/CreditNotes/CreditNoteListParams.cs b/src/Orb/Models/CreditNotes/CreditNoteListParams.cs index 554d98e8..5809003e 100644 --- a/src/Orb/Models/CreditNotes/CreditNoteListParams.cs +++ b/src/Orb/Models/CreditNotes/CreditNoteListParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.CreditNotes; @@ -10,70 +13,48 @@ namespace Orb.Models.CreditNotes; /// or external_customer_id. The credit notes will be returned in reverse chronological /// order by `creation_time`. /// -public sealed record class CreditNoteListParams : Orb::ParamsBase +public sealed record class CreditNoteListParams : ParamsBase { - public System::DateTime? CreatedAtGt + public DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[gt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[lt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -82,14 +63,8 @@ public sealed record class CreditNoteListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -97,30 +72,70 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public CreditNoteListParams() { } + + public CreditNoteListParams(CreditNoteListParams creditNoteListParams) + : base(creditNoteListParams) { } + + public CreditNoteListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditNoteListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CreditNoteListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/credit_notes") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/credit_notes") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/CustomExpiration.cs b/src/Orb/Models/CustomExpiration.cs index 8caeb9b9..5ea355bb 100644 --- a/src/Orb/Models/CustomExpiration.cs +++ b/src/Orb/Models/CustomExpiration.cs @@ -1,48 +1,36 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CustomExpirationProperties = Orb.Models.CustomExpirationProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomExpiration : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CustomExpiration : JsonModel { public required long Duration { - get - { - if (!this.Properties.TryGetValue("duration", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "duration"); } + init { JsonModel.Set(this._rawData, "duration", value); } } - public required CustomExpirationProperties::DurationUnit DurationUnit + public required ApiEnum DurationUnit { get { - if (!this.Properties.TryGetValue("duration_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("duration_unit"); + return JsonModel.GetNotNullClass>( + this.RawData, + "duration_unit" + ); } - set { this.Properties["duration_unit"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "duration_unit", value); } } + /// public override void Validate() { _ = this.Duration; @@ -51,18 +39,78 @@ public override void Validate() public CustomExpiration() { } + public CustomExpiration(CustomExpiration customExpiration) + : base(customExpiration) { } + + public CustomExpiration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomExpiration(Generic::Dictionary properties) + [SetsRequiredMembers] + CustomExpiration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CustomExpiration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomExpirationFromRaw : IFromRawJson +{ + /// + public CustomExpiration FromRawUnchecked(IReadOnlyDictionary rawData) => + CustomExpiration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CustomExpirationDurationUnitConverter))] +public enum CustomExpirationDurationUnit +{ + Day, + Month, +} + +sealed class CustomExpirationDurationUnitConverter : JsonConverter +{ + public override CustomExpirationDurationUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => CustomExpirationDurationUnit.Day, + "month" => CustomExpirationDurationUnit.Month, + _ => (CustomExpirationDurationUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomExpirationDurationUnit value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + CustomExpirationDurationUnit.Day => "day", + CustomExpirationDurationUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/CustomExpirationProperties/DurationUnit.cs b/src/Orb/Models/CustomExpirationProperties/DurationUnit.cs deleted file mode 100644 index b33c3e72..00000000 --- a/src/Orb/Models/CustomExpirationProperties/DurationUnit.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CustomExpirationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DurationUnit(string value) : Orb::IEnum -{ - public static readonly DurationUnit Day = new("day"); - - public static readonly DurationUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DurationUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CustomerMinified.cs b/src/Orb/Models/CustomerMinified.cs index 5a196a65..3c13f2a8 100644 --- a/src/Orb/Models/CustomerMinified.cs +++ b/src/Orb/Models/CustomerMinified.cs @@ -1,48 +1,28 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomerMinified : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CustomerMinified : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required string? ExternalCustomerID { - get - { - if (!this.Properties.TryGetValue("external_customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_customer_id"); } + init { JsonModel.Set(this._rawData, "external_customer_id", value); } } + /// public override void Validate() { _ = this.ID; @@ -51,18 +31,34 @@ public override void Validate() public CustomerMinified() { } + public CustomerMinified(CustomerMinified customerMinified) + : base(customerMinified) { } + + public CustomerMinified(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomerMinified(Generic::Dictionary properties) + [SetsRequiredMembers] + CustomerMinified(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CustomerMinified FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CustomerMinifiedFromRaw : IFromRawJson +{ + /// + public CustomerMinified FromRawUnchecked(IReadOnlyDictionary rawData) => + CustomerMinified.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/CustomerTaxID.cs b/src/Orb/Models/CustomerTaxID.cs index 4c9d3e69..38fb856e 100644 --- a/src/Orb/Models/CustomerTaxID.cs +++ b/src/Orb/Models/CustomerTaxID.cs @@ -1,9 +1,10 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CustomerTaxIDProperties = Orb.Models.CustomerTaxIDProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; @@ -12,156 +13,130 @@ namespace Orb.Models; /// Tax IDs are commonly required to be displayed on customer invoices, which are /// added to the headers of invoices. /// -/// ### Supported Tax ID Countries and Types +/// ### Supported Tax ID Countries and Types /// -/// | Country | Type | Description -/// | |----------------|--------------|---------------------------------------------| -/// | Andorra | `ad_nrt` | Andorran NRT Number -/// | | Argentina | `ar_cuit` | Argentinian Tax ID Number -/// | | Australia | `au_abn` | Australian Business Number (AU ABN) -/// | | Australia | `au_arn` | Australian Taxation Office Reference -/// Number | | Austria | `eu_vat` | European VAT Number -/// | | Bahrain | `bh_vat` | Bahraini VAT Number -/// | | Belgium | `eu_vat` | European VAT Number -/// | | Bolivia | `bo_tin` | Bolivian Tax ID -/// | | Brazil | `br_cnpj` | Brazilian CNPJ Number -/// | | Brazil | `br_cpf` | Brazilian CPF Number -/// | | Bulgaria | `bg_uic` | Bulgaria Unified -/// Identification Code | | Bulgaria | `eu_vat` | European VAT Number -/// | | Canada | `ca_bn` | Canadian BN -/// | | Canada | `ca_gst_hst` | Canadian GST/HST -/// Number | | Canada | `ca_pst_bc` | Canadian PST Number -/// (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number -/// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number -/// (Saskatchewan) | | Canada | `ca_qst` | Canadian QST Number -/// (Québec) | | Chile | `cl_tin` | Chilean TIN -/// | | China | `cn_tin` | Chinese Tax ID -/// | | Colombia | `co_nit` | Colombian NIT -/// Number | | Costa Rica | `cr_tin` | Costa Rican -/// Tax ID | | Croatia | `eu_vat` | European -/// VAT Number | | Cyprus | `eu_vat` | European -/// VAT Number | | Czech Republic | `eu_vat` | European -/// VAT Number | | Denmark | `eu_vat` | European -/// VAT Number | | Dominican Republic | `do_rcn` | Dominican -/// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian -/// RUC Number | | Egypt | `eg_tin` | Egyptian -/// Tax Identification Number | | El Salvador | `sv_nit` | -/// El Salvadorian NIT Number | | Estonia | `eu_vat` | European -/// VAT Number | | EU | `eu_oss_vat` | European One Stop Shop VAT Number -/// for non-Union scheme | | Finland | `eu_vat` | European VAT Number -/// | | France | `eu_vat` | European VAT Number -/// | | Georgia | `ge_vat` | Georgian VAT -/// | | Germany | `eu_vat` | European -/// VAT Number | | Greece | `eu_vat` | European -/// VAT Number | | Hong Kong | `hk_br` | Hong -/// Kong BR Number | | Hungary | `eu_vat` -/// | European VAT Number | | Hungary | `hu_tin` -/// | Hungary Tax Number (adószám) | | Iceland | -/// `is_vat` | Icelandic VAT | | India -/// | `in_gst` | Indian GST Number | -/// | Indonesia | `id_npwp` | Indonesian NPWP Number -/// | | Ireland | `eu_vat` | European VAT Number -/// | | Israel | `il_vat` | Israel VAT -/// | | Italy | `eu_vat` | European VAT Number -/// | | Japan | `jp_cn` | Japanese Corporate -/// Number (*Hōjin Bangō*) | | Japan | `jp_rn` | Japanese Registered -/// Foreign Businesses' Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) -/// | | Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku -/// Bangō*) | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification -/// Number | | Kenya | `ke_pin` | Kenya Revenue Authority -/// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number -/// | | Liechtenstein | `li_uid` | Liechtensteinian -/// UID Number | | Lithuania | `eu_vat` | European VAT Number -/// | | Luxembourg | `eu_vat` | European VAT Number -/// | | Malaysia | `my_frp` | Malaysian FRP Number -/// | | Malaysia | `my_itn` | Malaysian ITN | | -/// Malaysia | `my_sst` | Malaysian SST Number | | Malta -/// | `eu_vat ` | European VAT Number | | Mexico -/// | `mx_rfc` | Mexican RFC Number | | Netherlands | `eu_vat` -/// | European VAT Number | | New Zealand | `nz_gst` | New -/// Zealand GST Number | | Nigeria | `ng_tin` | Nigerian -/// Tax Identification Number | | Norway | `no_vat` | Norwegian VAT Number -/// | | Norway | `no_voec` | Norwegian VAT on e-commerce Number -/// | | Oman | `om_vat` | Omani VAT Number | | Peru -/// | `pe_ruc` | Peruvian RUC Number | | Philippines -/// | `ph_tin ` | Philippines Tax Identification Number | | Poland | `eu_vat` -/// | European VAT Number | | Portugal | `eu_vat` | European -/// VAT Number | | Romania | `eu_vat` | European VAT Number -/// | | Romania | `ro_tin` | Romanian Tax ID Number -/// | | Russia | `ru_inn` | Russian INN -/// | | Russia | `ru_kpp` | Russian KPP | | -/// Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | Serbia -/// | `rs_pib` | Serbian PIB Number | | Singapore | -/// `sg_gst` | Singaporean GST | | Singapore | `sg_uen` -/// | Singaporean UEN | | Slovakia | `eu_vat` -/// | European VAT Number | | Slovenia | `eu_vat` | European -/// VAT Number | | Slovenia | `si_tin` | Slovenia Tax -/// Number (davčna številka) | | South Africa | `za_vat` -/// | South African VAT Number | | South Korea -/// | `kr_brn` | Korean BRN | | Spain -/// | `es_cif` | Spanish NIF Number (previously Spanish CIF Number) | -/// | Spain | `eu_vat` | European VAT Number -/// | | Sweden | `eu_vat` | European VAT Number -/// | | Switzerland | `ch_vat` | Switzerland VAT -/// Number | | Taiwan | `tw_vat` | Taiwanese -/// VAT | | Thailand | `th_vat` -/// | Thai VAT | | Turkey -/// | `tr_tin` | Turkish Tax Identification Number | | Ukraine -/// | `ua_vat` | Ukrainian VAT | | -/// United Arab Emirates | `ae_trn` | United Arab Emirates TRN -/// | | United Kingdom | `eu_vat` | Northern Ireland VAT Number -/// | | United Kingdom | `gb_vat` | United Kingdom VAT -/// Number | | United States | `us_ein` | United -/// States EIN | | Uruguay | `uy_ruc` -/// | Uruguayan RUC Number | | Venezuela -/// | `ve_rif` | Venezuelan RIF Number | | Vietnam -/// | `vn_tin` | Vietnamese Tax ID Number | +/// | Country | Type | Description | |---------|------|-------------| | Albania +/// | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` | Andorran +/// NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number | | Argentina +/// | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` | Armenia Tax +/// Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification Number +/// | | Australia | `au_abn` | Australian Business Number (AU ABN) | | Australia +/// | `au_arn` | Australian Taxation Office Reference Number | | Austria | `eu_vat` +/// | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax Identification +/// Number | | Bahamas | `bs_tin` | Bahamas Tax Identification Number | | Bahrain +/// | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` | Bangladesh Business +/// Identification Number | | Barbados | `bb_tin` | Barbados Tax Identification Number +/// | | Belarus | `by_tin` | Belarus TIN Number | | Belgium | `eu_vat` | European +/// VAT Number | | Benin | `bj_ifu` | Benin Tax Identification Number (Identifiant +/// Fiscal Unique) | | Bolivia | `bo_tin` | Bolivian Tax ID | | Bosnia and Herzegovina +/// | `ba_tin` | Bosnia and Herzegovina Tax Identification Number | | Brazil | `br_cnpj` +/// | Brazilian CNPJ Number | | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria +/// | `bg_uic` | Bulgaria Unified Identification Code | | Bulgaria | `eu_vat` | European +/// VAT Number | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number +/// (Numéro d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification +/// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro d'Identifiant +/// fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada | `ca_gst_hst` | +/// Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian PST Number (British +/// Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number (Manitoba) | | Canada +/// | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian +/// QST Number (Québec) | | Cape Verde | `cv_nif` | Cape Verde Tax Identification +/// Number (Número de Identificação Fiscal) | | Chile | `cl_tin` | Chilean TIN | +/// | China | `cn_tin` | Chinese Tax ID | | Colombia | `co_nit` | Colombian NIT Number +/// | | Congo-Kinshasa | `cd_nif` | Congo (DR) Tax Identification Number (Número de +/// Identificação Fiscal) | | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia +/// | `eu_vat` | European VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification +/// Number (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | +/// `eu_vat` | European VAT Number | | Denmark | `eu_vat` | European VAT Number | +/// | Dominican Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` +/// | Ecuadorian RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number +/// | | El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` +/// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification Number +/// | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number for non-Union +/// scheme | | Finland | `eu_vat` | European VAT Number | | France | `eu_vat` | European +/// VAT Number | | Georgia | `ge_vat` | Georgian VAT | | Germany | `de_stn` | German +/// Tax Number (Steuernummer) | | Germany | `eu_vat` | European VAT Number | | Greece +/// | `eu_vat` | European VAT Number | | Guinea | `gn_nif` | Guinea Tax Identification +/// Number (Número de Identificação Fiscal) | | Hong Kong | `hk_br` | Hong Kong BR +/// Number | | Hungary | `eu_vat` | European VAT Number | | Hungary | `hu_tin` | +/// Hungary Tax Number (adószám) | | Iceland | `is_vat` | Icelandic VAT | | India +/// | `in_gst` | Indian GST Number | | Indonesia | `id_npwp` | Indonesian NPWP Number +/// | | Ireland | `eu_vat` | European VAT Number | | Israel | `il_vat` | Israel VAT +/// | | Italy | `eu_vat` | European VAT Number | | Japan | `jp_cn` | Japanese Corporate +/// Number (*Hōjin Bangō*) | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' +/// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` +/// | Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` +/// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya Revenue +/// Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` | Kyrgyzstan +/// Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification Number +/// | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` | Liechtensteinian +/// UID Number | | Liechtenstein | `li_vat` | Liechtenstein VAT Number | | Lithuania +/// | `eu_vat` | European VAT Number | | Luxembourg | `eu_vat` | European VAT Number +/// | | Malaysia | `my_frp` | Malaysian FRP Number | | Malaysia | `my_itn` | Malaysian +/// ITN | | Malaysia | `my_sst` | Malaysian SST Number | | Malta | `eu_vat` | European +/// VAT Number | | Mauritania | `mr_nif` | Mauritania Tax Identification Number (Número +/// de Identificação Fiscal) | | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova +/// | `md_vat` | Moldova VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number +/// | | Morocco | `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number +/// | | Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | +/// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification Number +/// | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern Ireland +/// | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | Norwegian VAT +/// Number | | Norway | `no_voec` | Norwegian VAT on e-commerce Number | | Oman | +/// `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian RUC Number | | Philippines +/// | `ph_tin` | Philippines Tax Identification Number | | Poland | `eu_vat` | European +/// VAT Number | | Portugal | `eu_vat` | European VAT Number | | Romania | `eu_vat` +/// | European VAT Number | | Romania | `ro_tin` | Romanian Tax ID Number | | Russia +/// | `ru_inn` | Russian INN | | Russia | `ru_kpp` | Russian KPP | | Saudi Arabia +/// | `sa_vat` | Saudi Arabia VAT | | Senegal | `sn_ninea` | Senegal NINEA Number +/// | | Serbia | `rs_pib` | Serbian PIB Number | | Singapore | `sg_gst` | Singaporean +/// GST | | Singapore | `sg_uen` | Singaporean UEN | | Slovakia | `eu_vat` | European +/// VAT Number | | Slovenia | `eu_vat` | European VAT Number | | Slovenia | `si_tin` +/// | Slovenia Tax Number (davčna številka) | | South Africa | `za_vat` | South African +/// VAT Number | | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish +/// NIF Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT +/// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` | European +/// VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number | | Switzerland +/// | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` | Taiwanese VAT | | +/// Tajikistan | `tj_tin` | Tajikistan Tax Identification Number | | Tanzania | `tz_vat` +/// | Tanzania VAT Number | | Thailand | `th_vat` | Thai VAT | | Turkey | `tr_tin` +/// | Turkish Tax Identification Number | | Uganda | `ug_tin` | Uganda Tax Identification +/// Number | | Ukraine | `ua_vat` | Ukrainian VAT | | United Arab Emirates | `ae_trn` +/// | United Arab Emirates TRN | | United Kingdom | `gb_vat` | United Kingdom VAT +/// Number | | United States | `us_ein` | United States EIN | | Uruguay | `uy_ruc` +/// | Uruguayan RUC Number | | Uzbekistan | `uz_tin` | Uzbekistan TIN Number | | +/// Uzbekistan | `uz_vat` | Uzbekistan VAT Number | | Venezuela | `ve_rif` | Venezuelan +/// RIF Number | | Vietnam | `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` +/// | Zambia Tax Identification Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification +/// Number | /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomerTaxID : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CustomerTaxID : JsonModel { - public required CustomerTaxIDProperties::Country Country + public required ApiEnum Country { - get - { - if (!this.Properties.TryGetValue("country", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "country", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("country"); - } - set { this.Properties["country"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "country"); } + init { JsonModel.Set(this._rawData, "country", value); } } - public required CustomerTaxIDProperties::Type Type + public required ApiEnum Type { get { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "type", value); } } public required string Value { - get - { - if (!this.Properties.TryGetValue("value", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("value", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("value"); - } - set { this.Properties["value"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "value"); } + init { JsonModel.Set(this._rawData, "value", value); } } + /// public override void Validate() { this.Country.Validate(); @@ -171,18 +146,770 @@ public override void Validate() public CustomerTaxID() { } + public CustomerTaxID(CustomerTaxID customerTaxID) + : base(customerTaxID) { } + + public CustomerTaxID(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomerTaxID(Generic::Dictionary properties) + [SetsRequiredMembers] + CustomerTaxID(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static CustomerTaxID FromRawUnchecked( - Generic::Dictionary properties + /// + public static CustomerTaxID FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerTaxIDFromRaw : IFromRawJson +{ + /// + public CustomerTaxID FromRawUnchecked(IReadOnlyDictionary rawData) => + CustomerTaxID.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CountryConverter))] +public enum Country +{ + Ad, + Ae, + Al, + Am, + Ao, + Ar, + At, + Au, + Aw, + Az, + Ba, + Bb, + Bd, + Be, + Bf, + Bg, + Bh, + Bj, + Bo, + Br, + Bs, + By, + Ca, + Cd, + Ch, + Cl, + Cm, + Cn, + Co, + Cr, + Cv, + De, + Cy, + Cz, + Dk, + Do, + Ec, + Ee, + Eg, + Es, + Et, + Eu, + Fi, + Fr, + GB, + Ge, + Gn, + Gr, + Hk, + Hr, + Hu, + ID, + Ie, + Il, + In, + Is, + It, + Jp, + Ke, + Kg, + Kh, + Kr, + Kz, + La, + Li, + Lt, + Lu, + Lv, + Ma, + Md, + Me, + Mk, + Mr, + Mt, + Mx, + My, + Ng, + Nl, + No, + Np, + Nz, + Om, + Pe, + Ph, + Pl, + Pt, + Ro, + Rs, + Ru, + Sa, + Se, + Sg, + Si, + Sk, + Sn, + Sr, + Sv, + Th, + Tj, + Tr, + Tw, + Tz, + Ua, + Ug, + Us, + Uy, + Uz, + Ve, + Vn, + Za, + Zm, + Zw, +} + +sealed class CountryConverter : JsonConverter +{ + public override Country Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "AD" => Country.Ad, + "AE" => Country.Ae, + "AL" => Country.Al, + "AM" => Country.Am, + "AO" => Country.Ao, + "AR" => Country.Ar, + "AT" => Country.At, + "AU" => Country.Au, + "AW" => Country.Aw, + "AZ" => Country.Az, + "BA" => Country.Ba, + "BB" => Country.Bb, + "BD" => Country.Bd, + "BE" => Country.Be, + "BF" => Country.Bf, + "BG" => Country.Bg, + "BH" => Country.Bh, + "BJ" => Country.Bj, + "BO" => Country.Bo, + "BR" => Country.Br, + "BS" => Country.Bs, + "BY" => Country.By, + "CA" => Country.Ca, + "CD" => Country.Cd, + "CH" => Country.Ch, + "CL" => Country.Cl, + "CM" => Country.Cm, + "CN" => Country.Cn, + "CO" => Country.Co, + "CR" => Country.Cr, + "CV" => Country.Cv, + "DE" => Country.De, + "CY" => Country.Cy, + "CZ" => Country.Cz, + "DK" => Country.Dk, + "DO" => Country.Do, + "EC" => Country.Ec, + "EE" => Country.Ee, + "EG" => Country.Eg, + "ES" => Country.Es, + "ET" => Country.Et, + "EU" => Country.Eu, + "FI" => Country.Fi, + "FR" => Country.Fr, + "GB" => Country.GB, + "GE" => Country.Ge, + "GN" => Country.Gn, + "GR" => Country.Gr, + "HK" => Country.Hk, + "HR" => Country.Hr, + "HU" => Country.Hu, + "ID" => Country.ID, + "IE" => Country.Ie, + "IL" => Country.Il, + "IN" => Country.In, + "IS" => Country.Is, + "IT" => Country.It, + "JP" => Country.Jp, + "KE" => Country.Ke, + "KG" => Country.Kg, + "KH" => Country.Kh, + "KR" => Country.Kr, + "KZ" => Country.Kz, + "LA" => Country.La, + "LI" => Country.Li, + "LT" => Country.Lt, + "LU" => Country.Lu, + "LV" => Country.Lv, + "MA" => Country.Ma, + "MD" => Country.Md, + "ME" => Country.Me, + "MK" => Country.Mk, + "MR" => Country.Mr, + "MT" => Country.Mt, + "MX" => Country.Mx, + "MY" => Country.My, + "NG" => Country.Ng, + "NL" => Country.Nl, + "NO" => Country.No, + "NP" => Country.Np, + "NZ" => Country.Nz, + "OM" => Country.Om, + "PE" => Country.Pe, + "PH" => Country.Ph, + "PL" => Country.Pl, + "PT" => Country.Pt, + "RO" => Country.Ro, + "RS" => Country.Rs, + "RU" => Country.Ru, + "SA" => Country.Sa, + "SE" => Country.Se, + "SG" => Country.Sg, + "SI" => Country.Si, + "SK" => Country.Sk, + "SN" => Country.Sn, + "SR" => Country.Sr, + "SV" => Country.Sv, + "TH" => Country.Th, + "TJ" => Country.Tj, + "TR" => Country.Tr, + "TW" => Country.Tw, + "TZ" => Country.Tz, + "UA" => Country.Ua, + "UG" => Country.Ug, + "US" => Country.Us, + "UY" => Country.Uy, + "UZ" => Country.Uz, + "VE" => Country.Ve, + "VN" => Country.Vn, + "ZA" => Country.Za, + "ZM" => Country.Zm, + "ZW" => Country.Zw, + _ => (Country)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Country value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Country.Ad => "AD", + Country.Ae => "AE", + Country.Al => "AL", + Country.Am => "AM", + Country.Ao => "AO", + Country.Ar => "AR", + Country.At => "AT", + Country.Au => "AU", + Country.Aw => "AW", + Country.Az => "AZ", + Country.Ba => "BA", + Country.Bb => "BB", + Country.Bd => "BD", + Country.Be => "BE", + Country.Bf => "BF", + Country.Bg => "BG", + Country.Bh => "BH", + Country.Bj => "BJ", + Country.Bo => "BO", + Country.Br => "BR", + Country.Bs => "BS", + Country.By => "BY", + Country.Ca => "CA", + Country.Cd => "CD", + Country.Ch => "CH", + Country.Cl => "CL", + Country.Cm => "CM", + Country.Cn => "CN", + Country.Co => "CO", + Country.Cr => "CR", + Country.Cv => "CV", + Country.De => "DE", + Country.Cy => "CY", + Country.Cz => "CZ", + Country.Dk => "DK", + Country.Do => "DO", + Country.Ec => "EC", + Country.Ee => "EE", + Country.Eg => "EG", + Country.Es => "ES", + Country.Et => "ET", + Country.Eu => "EU", + Country.Fi => "FI", + Country.Fr => "FR", + Country.GB => "GB", + Country.Ge => "GE", + Country.Gn => "GN", + Country.Gr => "GR", + Country.Hk => "HK", + Country.Hr => "HR", + Country.Hu => "HU", + Country.ID => "ID", + Country.Ie => "IE", + Country.Il => "IL", + Country.In => "IN", + Country.Is => "IS", + Country.It => "IT", + Country.Jp => "JP", + Country.Ke => "KE", + Country.Kg => "KG", + Country.Kh => "KH", + Country.Kr => "KR", + Country.Kz => "KZ", + Country.La => "LA", + Country.Li => "LI", + Country.Lt => "LT", + Country.Lu => "LU", + Country.Lv => "LV", + Country.Ma => "MA", + Country.Md => "MD", + Country.Me => "ME", + Country.Mk => "MK", + Country.Mr => "MR", + Country.Mt => "MT", + Country.Mx => "MX", + Country.My => "MY", + Country.Ng => "NG", + Country.Nl => "NL", + Country.No => "NO", + Country.Np => "NP", + Country.Nz => "NZ", + Country.Om => "OM", + Country.Pe => "PE", + Country.Ph => "PH", + Country.Pl => "PL", + Country.Pt => "PT", + Country.Ro => "RO", + Country.Rs => "RS", + Country.Ru => "RU", + Country.Sa => "SA", + Country.Se => "SE", + Country.Sg => "SG", + Country.Si => "SI", + Country.Sk => "SK", + Country.Sn => "SN", + Country.Sr => "SR", + Country.Sv => "SV", + Country.Th => "TH", + Country.Tj => "TJ", + Country.Tr => "TR", + Country.Tw => "TW", + Country.Tz => "TZ", + Country.Ua => "UA", + Country.Ug => "UG", + Country.Us => "US", + Country.Uy => "UY", + Country.Uz => "UZ", + Country.Ve => "VE", + Country.Vn => "VN", + Country.Za => "ZA", + Country.Zm => "ZM", + Country.Zw => "ZW", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CustomerTaxIDTypeConverter))] +public enum CustomerTaxIDType +{ + AdNrt, + AeTrn, + AlTin, + AmTin, + AoTin, + ArCuit, + EuVat, + AuAbn, + AuArn, + AwTin, + AzTin, + BaTin, + BbTin, + BdBin, + BfIfu, + BgUic, + BhVat, + BjIfu, + BoTin, + BrCnpj, + BrCpf, + BsTin, + ByTin, + CaBn, + CaGstHst, + CaPstBc, + CaPstMB, + CaPstSk, + CaQst, + CdNif, + ChUid, + ChVat, + ClTin, + CmNiu, + CnTin, + CoNit, + CrTin, + CvNif, + DeStn, + DoRcn, + EcRuc, + EgTin, + EsCif, + EtTin, + EuOssVat, + GBVat, + GeVat, + GnNif, + HkBr, + HrOib, + HuTin, + IDNpwp, + IlVat, + InGst, + IsVat, + JpCn, + JpRn, + JpTrn, + KePin, + KgTin, + KhTin, + KrBrn, + KzBin, + LaTin, + LiUid, + LiVat, + MaVat, + MdVat, + MePib, + MkVat, + MrNif, + MxRfc, + MyFrp, + MyItn, + MySst, + NgTin, + NoVat, + NoVoec, + NpPan, + NzGst, + OmVat, + PeRuc, + PhTin, + RoTin, + RsPib, + RuInn, + RuKpp, + SaVat, + SgGst, + SgUen, + SiTin, + SnNinea, + SrFin, + SvNit, + ThVat, + TjTin, + TrTin, + TwVat, + TzVat, + UaVat, + UgTin, + UsEin, + UyRuc, + UzTin, + UzVat, + VeRif, + VnTin, + ZaVat, + ZmTin, + ZwTin, +} + +sealed class CustomerTaxIDTypeConverter : JsonConverter +{ + public override CustomerTaxIDType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "ad_nrt" => CustomerTaxIDType.AdNrt, + "ae_trn" => CustomerTaxIDType.AeTrn, + "al_tin" => CustomerTaxIDType.AlTin, + "am_tin" => CustomerTaxIDType.AmTin, + "ao_tin" => CustomerTaxIDType.AoTin, + "ar_cuit" => CustomerTaxIDType.ArCuit, + "eu_vat" => CustomerTaxIDType.EuVat, + "au_abn" => CustomerTaxIDType.AuAbn, + "au_arn" => CustomerTaxIDType.AuArn, + "aw_tin" => CustomerTaxIDType.AwTin, + "az_tin" => CustomerTaxIDType.AzTin, + "ba_tin" => CustomerTaxIDType.BaTin, + "bb_tin" => CustomerTaxIDType.BbTin, + "bd_bin" => CustomerTaxIDType.BdBin, + "bf_ifu" => CustomerTaxIDType.BfIfu, + "bg_uic" => CustomerTaxIDType.BgUic, + "bh_vat" => CustomerTaxIDType.BhVat, + "bj_ifu" => CustomerTaxIDType.BjIfu, + "bo_tin" => CustomerTaxIDType.BoTin, + "br_cnpj" => CustomerTaxIDType.BrCnpj, + "br_cpf" => CustomerTaxIDType.BrCpf, + "bs_tin" => CustomerTaxIDType.BsTin, + "by_tin" => CustomerTaxIDType.ByTin, + "ca_bn" => CustomerTaxIDType.CaBn, + "ca_gst_hst" => CustomerTaxIDType.CaGstHst, + "ca_pst_bc" => CustomerTaxIDType.CaPstBc, + "ca_pst_mb" => CustomerTaxIDType.CaPstMB, + "ca_pst_sk" => CustomerTaxIDType.CaPstSk, + "ca_qst" => CustomerTaxIDType.CaQst, + "cd_nif" => CustomerTaxIDType.CdNif, + "ch_uid" => CustomerTaxIDType.ChUid, + "ch_vat" => CustomerTaxIDType.ChVat, + "cl_tin" => CustomerTaxIDType.ClTin, + "cm_niu" => CustomerTaxIDType.CmNiu, + "cn_tin" => CustomerTaxIDType.CnTin, + "co_nit" => CustomerTaxIDType.CoNit, + "cr_tin" => CustomerTaxIDType.CrTin, + "cv_nif" => CustomerTaxIDType.CvNif, + "de_stn" => CustomerTaxIDType.DeStn, + "do_rcn" => CustomerTaxIDType.DoRcn, + "ec_ruc" => CustomerTaxIDType.EcRuc, + "eg_tin" => CustomerTaxIDType.EgTin, + "es_cif" => CustomerTaxIDType.EsCif, + "et_tin" => CustomerTaxIDType.EtTin, + "eu_oss_vat" => CustomerTaxIDType.EuOssVat, + "gb_vat" => CustomerTaxIDType.GBVat, + "ge_vat" => CustomerTaxIDType.GeVat, + "gn_nif" => CustomerTaxIDType.GnNif, + "hk_br" => CustomerTaxIDType.HkBr, + "hr_oib" => CustomerTaxIDType.HrOib, + "hu_tin" => CustomerTaxIDType.HuTin, + "id_npwp" => CustomerTaxIDType.IDNpwp, + "il_vat" => CustomerTaxIDType.IlVat, + "in_gst" => CustomerTaxIDType.InGst, + "is_vat" => CustomerTaxIDType.IsVat, + "jp_cn" => CustomerTaxIDType.JpCn, + "jp_rn" => CustomerTaxIDType.JpRn, + "jp_trn" => CustomerTaxIDType.JpTrn, + "ke_pin" => CustomerTaxIDType.KePin, + "kg_tin" => CustomerTaxIDType.KgTin, + "kh_tin" => CustomerTaxIDType.KhTin, + "kr_brn" => CustomerTaxIDType.KrBrn, + "kz_bin" => CustomerTaxIDType.KzBin, + "la_tin" => CustomerTaxIDType.LaTin, + "li_uid" => CustomerTaxIDType.LiUid, + "li_vat" => CustomerTaxIDType.LiVat, + "ma_vat" => CustomerTaxIDType.MaVat, + "md_vat" => CustomerTaxIDType.MdVat, + "me_pib" => CustomerTaxIDType.MePib, + "mk_vat" => CustomerTaxIDType.MkVat, + "mr_nif" => CustomerTaxIDType.MrNif, + "mx_rfc" => CustomerTaxIDType.MxRfc, + "my_frp" => CustomerTaxIDType.MyFrp, + "my_itn" => CustomerTaxIDType.MyItn, + "my_sst" => CustomerTaxIDType.MySst, + "ng_tin" => CustomerTaxIDType.NgTin, + "no_vat" => CustomerTaxIDType.NoVat, + "no_voec" => CustomerTaxIDType.NoVoec, + "np_pan" => CustomerTaxIDType.NpPan, + "nz_gst" => CustomerTaxIDType.NzGst, + "om_vat" => CustomerTaxIDType.OmVat, + "pe_ruc" => CustomerTaxIDType.PeRuc, + "ph_tin" => CustomerTaxIDType.PhTin, + "ro_tin" => CustomerTaxIDType.RoTin, + "rs_pib" => CustomerTaxIDType.RsPib, + "ru_inn" => CustomerTaxIDType.RuInn, + "ru_kpp" => CustomerTaxIDType.RuKpp, + "sa_vat" => CustomerTaxIDType.SaVat, + "sg_gst" => CustomerTaxIDType.SgGst, + "sg_uen" => CustomerTaxIDType.SgUen, + "si_tin" => CustomerTaxIDType.SiTin, + "sn_ninea" => CustomerTaxIDType.SnNinea, + "sr_fin" => CustomerTaxIDType.SrFin, + "sv_nit" => CustomerTaxIDType.SvNit, + "th_vat" => CustomerTaxIDType.ThVat, + "tj_tin" => CustomerTaxIDType.TjTin, + "tr_tin" => CustomerTaxIDType.TrTin, + "tw_vat" => CustomerTaxIDType.TwVat, + "tz_vat" => CustomerTaxIDType.TzVat, + "ua_vat" => CustomerTaxIDType.UaVat, + "ug_tin" => CustomerTaxIDType.UgTin, + "us_ein" => CustomerTaxIDType.UsEin, + "uy_ruc" => CustomerTaxIDType.UyRuc, + "uz_tin" => CustomerTaxIDType.UzTin, + "uz_vat" => CustomerTaxIDType.UzVat, + "ve_rif" => CustomerTaxIDType.VeRif, + "vn_tin" => CustomerTaxIDType.VnTin, + "za_vat" => CustomerTaxIDType.ZaVat, + "zm_tin" => CustomerTaxIDType.ZmTin, + "zw_tin" => CustomerTaxIDType.ZwTin, + _ => (CustomerTaxIDType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerTaxIDType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + CustomerTaxIDType.AdNrt => "ad_nrt", + CustomerTaxIDType.AeTrn => "ae_trn", + CustomerTaxIDType.AlTin => "al_tin", + CustomerTaxIDType.AmTin => "am_tin", + CustomerTaxIDType.AoTin => "ao_tin", + CustomerTaxIDType.ArCuit => "ar_cuit", + CustomerTaxIDType.EuVat => "eu_vat", + CustomerTaxIDType.AuAbn => "au_abn", + CustomerTaxIDType.AuArn => "au_arn", + CustomerTaxIDType.AwTin => "aw_tin", + CustomerTaxIDType.AzTin => "az_tin", + CustomerTaxIDType.BaTin => "ba_tin", + CustomerTaxIDType.BbTin => "bb_tin", + CustomerTaxIDType.BdBin => "bd_bin", + CustomerTaxIDType.BfIfu => "bf_ifu", + CustomerTaxIDType.BgUic => "bg_uic", + CustomerTaxIDType.BhVat => "bh_vat", + CustomerTaxIDType.BjIfu => "bj_ifu", + CustomerTaxIDType.BoTin => "bo_tin", + CustomerTaxIDType.BrCnpj => "br_cnpj", + CustomerTaxIDType.BrCpf => "br_cpf", + CustomerTaxIDType.BsTin => "bs_tin", + CustomerTaxIDType.ByTin => "by_tin", + CustomerTaxIDType.CaBn => "ca_bn", + CustomerTaxIDType.CaGstHst => "ca_gst_hst", + CustomerTaxIDType.CaPstBc => "ca_pst_bc", + CustomerTaxIDType.CaPstMB => "ca_pst_mb", + CustomerTaxIDType.CaPstSk => "ca_pst_sk", + CustomerTaxIDType.CaQst => "ca_qst", + CustomerTaxIDType.CdNif => "cd_nif", + CustomerTaxIDType.ChUid => "ch_uid", + CustomerTaxIDType.ChVat => "ch_vat", + CustomerTaxIDType.ClTin => "cl_tin", + CustomerTaxIDType.CmNiu => "cm_niu", + CustomerTaxIDType.CnTin => "cn_tin", + CustomerTaxIDType.CoNit => "co_nit", + CustomerTaxIDType.CrTin => "cr_tin", + CustomerTaxIDType.CvNif => "cv_nif", + CustomerTaxIDType.DeStn => "de_stn", + CustomerTaxIDType.DoRcn => "do_rcn", + CustomerTaxIDType.EcRuc => "ec_ruc", + CustomerTaxIDType.EgTin => "eg_tin", + CustomerTaxIDType.EsCif => "es_cif", + CustomerTaxIDType.EtTin => "et_tin", + CustomerTaxIDType.EuOssVat => "eu_oss_vat", + CustomerTaxIDType.GBVat => "gb_vat", + CustomerTaxIDType.GeVat => "ge_vat", + CustomerTaxIDType.GnNif => "gn_nif", + CustomerTaxIDType.HkBr => "hk_br", + CustomerTaxIDType.HrOib => "hr_oib", + CustomerTaxIDType.HuTin => "hu_tin", + CustomerTaxIDType.IDNpwp => "id_npwp", + CustomerTaxIDType.IlVat => "il_vat", + CustomerTaxIDType.InGst => "in_gst", + CustomerTaxIDType.IsVat => "is_vat", + CustomerTaxIDType.JpCn => "jp_cn", + CustomerTaxIDType.JpRn => "jp_rn", + CustomerTaxIDType.JpTrn => "jp_trn", + CustomerTaxIDType.KePin => "ke_pin", + CustomerTaxIDType.KgTin => "kg_tin", + CustomerTaxIDType.KhTin => "kh_tin", + CustomerTaxIDType.KrBrn => "kr_brn", + CustomerTaxIDType.KzBin => "kz_bin", + CustomerTaxIDType.LaTin => "la_tin", + CustomerTaxIDType.LiUid => "li_uid", + CustomerTaxIDType.LiVat => "li_vat", + CustomerTaxIDType.MaVat => "ma_vat", + CustomerTaxIDType.MdVat => "md_vat", + CustomerTaxIDType.MePib => "me_pib", + CustomerTaxIDType.MkVat => "mk_vat", + CustomerTaxIDType.MrNif => "mr_nif", + CustomerTaxIDType.MxRfc => "mx_rfc", + CustomerTaxIDType.MyFrp => "my_frp", + CustomerTaxIDType.MyItn => "my_itn", + CustomerTaxIDType.MySst => "my_sst", + CustomerTaxIDType.NgTin => "ng_tin", + CustomerTaxIDType.NoVat => "no_vat", + CustomerTaxIDType.NoVoec => "no_voec", + CustomerTaxIDType.NpPan => "np_pan", + CustomerTaxIDType.NzGst => "nz_gst", + CustomerTaxIDType.OmVat => "om_vat", + CustomerTaxIDType.PeRuc => "pe_ruc", + CustomerTaxIDType.PhTin => "ph_tin", + CustomerTaxIDType.RoTin => "ro_tin", + CustomerTaxIDType.RsPib => "rs_pib", + CustomerTaxIDType.RuInn => "ru_inn", + CustomerTaxIDType.RuKpp => "ru_kpp", + CustomerTaxIDType.SaVat => "sa_vat", + CustomerTaxIDType.SgGst => "sg_gst", + CustomerTaxIDType.SgUen => "sg_uen", + CustomerTaxIDType.SiTin => "si_tin", + CustomerTaxIDType.SnNinea => "sn_ninea", + CustomerTaxIDType.SrFin => "sr_fin", + CustomerTaxIDType.SvNit => "sv_nit", + CustomerTaxIDType.ThVat => "th_vat", + CustomerTaxIDType.TjTin => "tj_tin", + CustomerTaxIDType.TrTin => "tr_tin", + CustomerTaxIDType.TwVat => "tw_vat", + CustomerTaxIDType.TzVat => "tz_vat", + CustomerTaxIDType.UaVat => "ua_vat", + CustomerTaxIDType.UgTin => "ug_tin", + CustomerTaxIDType.UsEin => "us_ein", + CustomerTaxIDType.UyRuc => "uy_ruc", + CustomerTaxIDType.UzTin => "uz_tin", + CustomerTaxIDType.UzVat => "uz_vat", + CustomerTaxIDType.VeRif => "ve_rif", + CustomerTaxIDType.VnTin => "vn_tin", + CustomerTaxIDType.ZaVat => "za_vat", + CustomerTaxIDType.ZmTin => "zm_tin", + CustomerTaxIDType.ZwTin => "zw_tin", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/CustomerTaxIDProperties/Country.cs b/src/Orb/Models/CustomerTaxIDProperties/Country.cs deleted file mode 100644 index 49c6cac3..00000000 --- a/src/Orb/Models/CustomerTaxIDProperties/Country.cs +++ /dev/null @@ -1,348 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CustomerTaxIDProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Country(string value) : Orb::IEnum -{ - public static readonly Country Ad = new("AD"); - - public static readonly Country Ae = new("AE"); - - public static readonly Country Ar = new("AR"); - - public static readonly Country At = new("AT"); - - public static readonly Country Au = new("AU"); - - public static readonly Country Be = new("BE"); - - public static readonly Country Bg = new("BG"); - - public static readonly Country Bh = new("BH"); - - public static readonly Country Bo = new("BO"); - - public static readonly Country Br = new("BR"); - - public static readonly Country Ca = new("CA"); - - public static readonly Country Ch = new("CH"); - - public static readonly Country Cl = new("CL"); - - public static readonly Country Cn = new("CN"); - - public static readonly Country Co = new("CO"); - - public static readonly Country Cr = new("CR"); - - public static readonly Country Cy = new("CY"); - - public static readonly Country Cz = new("CZ"); - - public static readonly Country De = new("DE"); - - public static readonly Country Dk = new("DK"); - - public static readonly Country Ee = new("EE"); - - public static readonly Country Do = new("DO"); - - public static readonly Country Ec = new("EC"); - - public static readonly Country Eg = new("EG"); - - public static readonly Country Es = new("ES"); - - public static readonly Country Eu = new("EU"); - - public static readonly Country Fi = new("FI"); - - public static readonly Country Fr = new("FR"); - - public static readonly Country GB = new("GB"); - - public static readonly Country Ge = new("GE"); - - public static readonly Country Gr = new("GR"); - - public static readonly Country Hk = new("HK"); - - public static readonly Country Hr = new("HR"); - - public static readonly Country Hu = new("HU"); - - public static readonly Country ID = new("ID"); - - public static readonly Country Ie = new("IE"); - - public static readonly Country Il = new("IL"); - - public static readonly Country In = new("IN"); - - public static readonly Country Is = new("IS"); - - public static readonly Country It = new("IT"); - - public static readonly Country Jp = new("JP"); - - public static readonly Country Ke = new("KE"); - - public static readonly Country Kr = new("KR"); - - public static readonly Country Kz = new("KZ"); - - public static readonly Country Li = new("LI"); - - public static readonly Country Lt = new("LT"); - - public static readonly Country Lu = new("LU"); - - public static readonly Country Lv = new("LV"); - - public static readonly Country Mt = new("MT"); - - public static readonly Country Mx = new("MX"); - - public static readonly Country My = new("MY"); - - public static readonly Country Ng = new("NG"); - - public static readonly Country Nl = new("NL"); - - public static readonly Country No = new("NO"); - - public static readonly Country Nz = new("NZ"); - - public static readonly Country Om = new("OM"); - - public static readonly Country Pe = new("PE"); - - public static readonly Country Ph = new("PH"); - - public static readonly Country Pl = new("PL"); - - public static readonly Country Pt = new("PT"); - - public static readonly Country Ro = new("RO"); - - public static readonly Country Rs = new("RS"); - - public static readonly Country Ru = new("RU"); - - public static readonly Country Sa = new("SA"); - - public static readonly Country Se = new("SE"); - - public static readonly Country Sg = new("SG"); - - public static readonly Country Si = new("SI"); - - public static readonly Country Sk = new("SK"); - - public static readonly Country Sv = new("SV"); - - public static readonly Country Th = new("TH"); - - public static readonly Country Tr = new("TR"); - - public static readonly Country Tw = new("TW"); - - public static readonly Country Ua = new("UA"); - - public static readonly Country Us = new("US"); - - public static readonly Country Uy = new("UY"); - - public static readonly Country Ve = new("VE"); - - public static readonly Country Vn = new("VN"); - - public static readonly Country Za = new("ZA"); - - readonly string _value = value; - - public enum Value - { - Ad, - Ae, - Ar, - At, - Au, - Be, - Bg, - Bh, - Bo, - Br, - Ca, - Ch, - Cl, - Cn, - Co, - Cr, - Cy, - Cz, - De, - Dk, - Ee, - Do, - Ec, - Eg, - Es, - Eu, - Fi, - Fr, - GB, - Ge, - Gr, - Hk, - Hr, - Hu, - ID, - Ie, - Il, - In, - Is, - It, - Jp, - Ke, - Kr, - Kz, - Li, - Lt, - Lu, - Lv, - Mt, - Mx, - My, - Ng, - Nl, - No, - Nz, - Om, - Pe, - Ph, - Pl, - Pt, - Ro, - Rs, - Ru, - Sa, - Se, - Sg, - Si, - Sk, - Sv, - Th, - Tr, - Tw, - Ua, - Us, - Uy, - Ve, - Vn, - Za, - } - - public Value Known() => - _value switch - { - "AD" => Value.Ad, - "AE" => Value.Ae, - "AR" => Value.Ar, - "AT" => Value.At, - "AU" => Value.Au, - "BE" => Value.Be, - "BG" => Value.Bg, - "BH" => Value.Bh, - "BO" => Value.Bo, - "BR" => Value.Br, - "CA" => Value.Ca, - "CH" => Value.Ch, - "CL" => Value.Cl, - "CN" => Value.Cn, - "CO" => Value.Co, - "CR" => Value.Cr, - "CY" => Value.Cy, - "CZ" => Value.Cz, - "DE" => Value.De, - "DK" => Value.Dk, - "EE" => Value.Ee, - "DO" => Value.Do, - "EC" => Value.Ec, - "EG" => Value.Eg, - "ES" => Value.Es, - "EU" => Value.Eu, - "FI" => Value.Fi, - "FR" => Value.Fr, - "GB" => Value.GB, - "GE" => Value.Ge, - "GR" => Value.Gr, - "HK" => Value.Hk, - "HR" => Value.Hr, - "HU" => Value.Hu, - "ID" => Value.ID, - "IE" => Value.Ie, - "IL" => Value.Il, - "IN" => Value.In, - "IS" => Value.Is, - "IT" => Value.It, - "JP" => Value.Jp, - "KE" => Value.Ke, - "KR" => Value.Kr, - "KZ" => Value.Kz, - "LI" => Value.Li, - "LT" => Value.Lt, - "LU" => Value.Lu, - "LV" => Value.Lv, - "MT" => Value.Mt, - "MX" => Value.Mx, - "MY" => Value.My, - "NG" => Value.Ng, - "NL" => Value.Nl, - "NO" => Value.No, - "NZ" => Value.Nz, - "OM" => Value.Om, - "PE" => Value.Pe, - "PH" => Value.Ph, - "PL" => Value.Pl, - "PT" => Value.Pt, - "RO" => Value.Ro, - "RS" => Value.Rs, - "RU" => Value.Ru, - "SA" => Value.Sa, - "SE" => Value.Se, - "SG" => Value.Sg, - "SI" => Value.Si, - "SK" => Value.Sk, - "SV" => Value.Sv, - "TH" => Value.Th, - "TR" => Value.Tr, - "TW" => Value.Tw, - "UA" => Value.Ua, - "US" => Value.Us, - "UY" => Value.Uy, - "VE" => Value.Ve, - "VN" => Value.Vn, - "ZA" => Value.Za, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Country FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/CustomerTaxIDProperties/Type.cs b/src/Orb/Models/CustomerTaxIDProperties/Type.cs deleted file mode 100644 index 661d989d..00000000 --- a/src/Orb/Models/CustomerTaxIDProperties/Type.cs +++ /dev/null @@ -1,320 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.CustomerTaxIDProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type AdNrt = new("ad_nrt"); - - public static readonly Type AeTrn = new("ae_trn"); - - public static readonly Type ArCuit = new("ar_cuit"); - - public static readonly Type EuVat = new("eu_vat"); - - public static readonly Type AuAbn = new("au_abn"); - - public static readonly Type AuArn = new("au_arn"); - - public static readonly Type BgUic = new("bg_uic"); - - public static readonly Type BhVat = new("bh_vat"); - - public static readonly Type BoTin = new("bo_tin"); - - public static readonly Type BrCnpj = new("br_cnpj"); - - public static readonly Type BrCpf = new("br_cpf"); - - public static readonly Type CaBn = new("ca_bn"); - - public static readonly Type CaGstHst = new("ca_gst_hst"); - - public static readonly Type CaPstBc = new("ca_pst_bc"); - - public static readonly Type CaPstMB = new("ca_pst_mb"); - - public static readonly Type CaPstSk = new("ca_pst_sk"); - - public static readonly Type CaQst = new("ca_qst"); - - public static readonly Type ChVat = new("ch_vat"); - - public static readonly Type ClTin = new("cl_tin"); - - public static readonly Type CnTin = new("cn_tin"); - - public static readonly Type CoNit = new("co_nit"); - - public static readonly Type CrTin = new("cr_tin"); - - public static readonly Type DoRcn = new("do_rcn"); - - public static readonly Type EcRuc = new("ec_ruc"); - - public static readonly Type EgTin = new("eg_tin"); - - public static readonly Type EsCif = new("es_cif"); - - public static readonly Type EuOssVat = new("eu_oss_vat"); - - public static readonly Type GBVat = new("gb_vat"); - - public static readonly Type GeVat = new("ge_vat"); - - public static readonly Type HkBr = new("hk_br"); - - public static readonly Type HuTin = new("hu_tin"); - - public static readonly Type IDNpwp = new("id_npwp"); - - public static readonly Type IlVat = new("il_vat"); - - public static readonly Type InGst = new("in_gst"); - - public static readonly Type IsVat = new("is_vat"); - - public static readonly Type JpCn = new("jp_cn"); - - public static readonly Type JpRn = new("jp_rn"); - - public static readonly Type JpTrn = new("jp_trn"); - - public static readonly Type KePin = new("ke_pin"); - - public static readonly Type KrBrn = new("kr_brn"); - - public static readonly Type KzBin = new("kz_bin"); - - public static readonly Type LiUid = new("li_uid"); - - public static readonly Type MxRfc = new("mx_rfc"); - - public static readonly Type MyFrp = new("my_frp"); - - public static readonly Type MyItn = new("my_itn"); - - public static readonly Type MySst = new("my_sst"); - - public static readonly Type NgTin = new("ng_tin"); - - public static readonly Type NoVat = new("no_vat"); - - public static readonly Type NoVoec = new("no_voec"); - - public static readonly Type NzGst = new("nz_gst"); - - public static readonly Type OmVat = new("om_vat"); - - public static readonly Type PeRuc = new("pe_ruc"); - - public static readonly Type PhTin = new("ph_tin"); - - public static readonly Type RoTin = new("ro_tin"); - - public static readonly Type RsPib = new("rs_pib"); - - public static readonly Type RuInn = new("ru_inn"); - - public static readonly Type RuKpp = new("ru_kpp"); - - public static readonly Type SaVat = new("sa_vat"); - - public static readonly Type SgGst = new("sg_gst"); - - public static readonly Type SgUen = new("sg_uen"); - - public static readonly Type SiTin = new("si_tin"); - - public static readonly Type SvNit = new("sv_nit"); - - public static readonly Type ThVat = new("th_vat"); - - public static readonly Type TrTin = new("tr_tin"); - - public static readonly Type TwVat = new("tw_vat"); - - public static readonly Type UaVat = new("ua_vat"); - - public static readonly Type UsEin = new("us_ein"); - - public static readonly Type UyRuc = new("uy_ruc"); - - public static readonly Type VeRif = new("ve_rif"); - - public static readonly Type VnTin = new("vn_tin"); - - public static readonly Type ZaVat = new("za_vat"); - - readonly string _value = value; - - public enum Value - { - AdNrt, - AeTrn, - ArCuit, - EuVat, - AuAbn, - AuArn, - BgUic, - BhVat, - BoTin, - BrCnpj, - BrCpf, - CaBn, - CaGstHst, - CaPstBc, - CaPstMB, - CaPstSk, - CaQst, - ChVat, - ClTin, - CnTin, - CoNit, - CrTin, - DoRcn, - EcRuc, - EgTin, - EsCif, - EuOssVat, - GBVat, - GeVat, - HkBr, - HuTin, - IDNpwp, - IlVat, - InGst, - IsVat, - JpCn, - JpRn, - JpTrn, - KePin, - KrBrn, - KzBin, - LiUid, - MxRfc, - MyFrp, - MyItn, - MySst, - NgTin, - NoVat, - NoVoec, - NzGst, - OmVat, - PeRuc, - PhTin, - RoTin, - RsPib, - RuInn, - RuKpp, - SaVat, - SgGst, - SgUen, - SiTin, - SvNit, - ThVat, - TrTin, - TwVat, - UaVat, - UsEin, - UyRuc, - VeRif, - VnTin, - ZaVat, - } - - public Value Known() => - _value switch - { - "ad_nrt" => Value.AdNrt, - "ae_trn" => Value.AeTrn, - "ar_cuit" => Value.ArCuit, - "eu_vat" => Value.EuVat, - "au_abn" => Value.AuAbn, - "au_arn" => Value.AuArn, - "bg_uic" => Value.BgUic, - "bh_vat" => Value.BhVat, - "bo_tin" => Value.BoTin, - "br_cnpj" => Value.BrCnpj, - "br_cpf" => Value.BrCpf, - "ca_bn" => Value.CaBn, - "ca_gst_hst" => Value.CaGstHst, - "ca_pst_bc" => Value.CaPstBc, - "ca_pst_mb" => Value.CaPstMB, - "ca_pst_sk" => Value.CaPstSk, - "ca_qst" => Value.CaQst, - "ch_vat" => Value.ChVat, - "cl_tin" => Value.ClTin, - "cn_tin" => Value.CnTin, - "co_nit" => Value.CoNit, - "cr_tin" => Value.CrTin, - "do_rcn" => Value.DoRcn, - "ec_ruc" => Value.EcRuc, - "eg_tin" => Value.EgTin, - "es_cif" => Value.EsCif, - "eu_oss_vat" => Value.EuOssVat, - "gb_vat" => Value.GBVat, - "ge_vat" => Value.GeVat, - "hk_br" => Value.HkBr, - "hu_tin" => Value.HuTin, - "id_npwp" => Value.IDNpwp, - "il_vat" => Value.IlVat, - "in_gst" => Value.InGst, - "is_vat" => Value.IsVat, - "jp_cn" => Value.JpCn, - "jp_rn" => Value.JpRn, - "jp_trn" => Value.JpTrn, - "ke_pin" => Value.KePin, - "kr_brn" => Value.KrBrn, - "kz_bin" => Value.KzBin, - "li_uid" => Value.LiUid, - "mx_rfc" => Value.MxRfc, - "my_frp" => Value.MyFrp, - "my_itn" => Value.MyItn, - "my_sst" => Value.MySst, - "ng_tin" => Value.NgTin, - "no_vat" => Value.NoVat, - "no_voec" => Value.NoVoec, - "nz_gst" => Value.NzGst, - "om_vat" => Value.OmVat, - "pe_ruc" => Value.PeRuc, - "ph_tin" => Value.PhTin, - "ro_tin" => Value.RoTin, - "rs_pib" => Value.RsPib, - "ru_inn" => Value.RuInn, - "ru_kpp" => Value.RuKpp, - "sa_vat" => Value.SaVat, - "sg_gst" => Value.SgGst, - "sg_uen" => Value.SgUen, - "si_tin" => Value.SiTin, - "sv_nit" => Value.SvNit, - "th_vat" => Value.ThVat, - "tr_tin" => Value.TrTin, - "tw_vat" => Value.TwVat, - "ua_vat" => Value.UaVat, - "us_ein" => Value.UsEin, - "uy_ruc" => Value.UyRuc, - "ve_rif" => Value.VeRif, - "vn_tin" => Value.VnTin, - "za_vat" => Value.ZaVat, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/AccountingProviderConfig.cs b/src/Orb/Models/Customers/AccountingProviderConfig.cs index 91028111..0b9d8dd3 100644 --- a/src/Orb/Models/Customers/AccountingProviderConfig.cs +++ b/src/Orb/Models/Customers/AccountingProviderConfig.cs @@ -1,54 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AccountingProviderConfig - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class AccountingProviderConfig : JsonModel { public required string ExternalProviderID { - get - { - if (!this.Properties.TryGetValue("external_provider_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_provider_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("external_provider_id"); - } - set - { - this.Properties["external_provider_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawData, "external_provider_id"); } + init { JsonModel.Set(this._rawData, "external_provider_id", value); } } public required string ProviderType { - get - { - if (!this.Properties.TryGetValue("provider_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "provider_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("provider_type"); - } - set { this.Properties["provider_type"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "provider_type"); } + init { JsonModel.Set(this._rawData, "provider_type", value); } } + /// public override void Validate() { _ = this.ExternalProviderID; @@ -57,18 +33,35 @@ public override void Validate() public AccountingProviderConfig() { } + public AccountingProviderConfig(AccountingProviderConfig accountingProviderConfig) + : base(accountingProviderConfig) { } + + public AccountingProviderConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AccountingProviderConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + AccountingProviderConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static AccountingProviderConfig FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class AccountingProviderConfigFromRaw : IFromRawJson +{ + /// + public AccountingProviderConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AccountingProviderConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/AddressInput.cs b/src/Orb/Models/Customers/AddressInput.cs index f74e5af9..14d83793 100644 --- a/src/Orb/Models/Customers/AddressInput.cs +++ b/src/Orb/Models/Customers/AddressInput.cs @@ -1,86 +1,52 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddressInput : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AddressInput : JsonModel { public string? City { - get - { - if (!this.Properties.TryGetValue("city", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["city"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "city"); } + init { JsonModel.Set(this._rawData, "city", value); } } public string? Country { - get - { - if (!this.Properties.TryGetValue("country", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["country"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "country"); } + init { JsonModel.Set(this._rawData, "country", value); } } public string? Line1 { - get - { - if (!this.Properties.TryGetValue("line1", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["line1"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "line1"); } + init { JsonModel.Set(this._rawData, "line1", value); } } public string? Line2 { - get - { - if (!this.Properties.TryGetValue("line2", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["line2"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "line2"); } + init { JsonModel.Set(this._rawData, "line2", value); } } public string? PostalCode { - get - { - if (!this.Properties.TryGetValue("postal_code", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["postal_code"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "postal_code"); } + init { JsonModel.Set(this._rawData, "postal_code", value); } } public string? State { - get - { - if (!this.Properties.TryGetValue("state", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["state"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "state"); } + init { JsonModel.Set(this._rawData, "state", value); } } + /// public override void Validate() { _ = this.City; @@ -93,18 +59,32 @@ public override void Validate() public AddressInput() { } + public AddressInput(AddressInput addressInput) + : base(addressInput) { } + + public AddressInput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddressInput(Generic::Dictionary properties) + [SetsRequiredMembers] + AddressInput(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static AddressInput FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static AddressInput FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class AddressInputFromRaw : IFromRawJson +{ + /// + public AddressInput FromRawUnchecked(IReadOnlyDictionary rawData) => + AddressInput.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParams.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParams.cs index 27f2dd23..b6e60f25 100644 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParams.cs +++ b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParams.cs @@ -1,51 +1,45 @@ -using BalanceTransactionCreateParamsProperties = Orb.Models.Customers.BalanceTransactions.BalanceTransactionCreateParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Customers.BalanceTransactions; /// -/// Creates an immutable balance transaction that updates the customer's balance and -/// returns back the newly created transaction. +/// Creates an immutable balance transaction that updates the customer's balance +/// and returns back the newly created transaction. /// -public sealed record class BalanceTransactionCreateParams : Orb::ParamsBase +public sealed record class BalanceTransactionCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string CustomerID; + public string? CustomerID { get; init; } public required string Amount { - get - { - if (!this.BodyProperties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.BodyProperties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "amount"); } + init { JsonModel.Set(this._rawBodyData, "amount", value); } } - public required BalanceTransactionCreateParamsProperties::Type Type + public required ApiEnum Type { get { - if (!this.BodyProperties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawBodyData, "type"); } - set { this.BodyProperties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "type", value); } } /// @@ -53,42 +47,129 @@ public required string Amount /// public string? Description { - get - { - if (!this.BodyProperties.TryGetValue("description", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "description"); } + init { JsonModel.Set(this._rawBodyData, "description", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["description"] = Json::JsonSerializer.SerializeToElement(value); } + public BalanceTransactionCreateParams() { } + + public BalanceTransactionCreateParams( + BalanceTransactionCreateParams balanceTransactionCreateParams + ) + : base(balanceTransactionCreateParams) + { + this._rawBodyData = [.. balanceTransactionCreateParams._rawBodyData]; + } + + public BalanceTransactionCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BalanceTransactionCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } +#pragma warning restore CS8618 - public override System::Uri Url(Orb::IOrbClient client) + /// + public static BalanceTransactionCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/balance_transactions", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter(typeof(global::Orb.Models.Customers.BalanceTransactions.TypeConverter))] +public enum Type +{ + Increment, + Decrement, +} + +sealed class TypeConverter : JsonConverter +{ + public override global::Orb.Models.Customers.BalanceTransactions.Type Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => global::Orb.Models.Customers.BalanceTransactions.Type.Increment, + "decrement" => global::Orb.Models.Customers.BalanceTransactions.Type.Decrement, + _ => (global::Orb.Models.Customers.BalanceTransactions.Type)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.BalanceTransactions.Type value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.BalanceTransactions.Type.Increment => "increment", + global::Orb.Models.Customers.BalanceTransactions.Type.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParamsProperties/Type.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParamsProperties/Type.cs deleted file mode 100644 index 5c16e2b7..00000000 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateParamsProperties/Type.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.BalanceTransactions.BalanceTransactionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Increment = new("increment"); - - public static readonly Type Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponse.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponse.cs index a22c76d6..b4eb68bd 100644 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponse.cs +++ b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponse.cs @@ -1,50 +1,40 @@ -using BalanceTransactionCreateResponseProperties = Orb.Models.Customers.BalanceTransactions.BalanceTransactionCreateResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.BalanceTransactions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BalanceTransactionCreateResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + BalanceTransactionCreateResponse, + BalanceTransactionCreateResponseFromRaw + >) +)] +public sealed record class BalanceTransactionCreateResponse : JsonModel { /// /// A unique id for this transaction. /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required BalanceTransactionCreateResponseProperties::Action Action + public required ApiEnum Action { get { - if (!this.Properties.TryGetValue("action", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "action", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("action"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "action"); } - set { this.Properties["action"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "action", value); } } /// @@ -52,51 +42,26 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The creation time of this transaction. /// - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } - public required Models::CreditNoteTiny? CreditNote + public required CreditNoteTiny? CreditNote { - get - { - if (!this.Properties.TryGetValue("credit_note", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["credit_note"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "credit_note"); } + init { JsonModel.Set(this._rawData, "credit_note", value); } } /// @@ -104,17 +69,8 @@ public required string Amount /// public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } /// @@ -122,72 +78,39 @@ public required string? Description /// public required string EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("ending_balance"); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required Models::InvoiceTiny? Invoice + public required InvoiceTiny? Invoice { - get - { - if (!this.Properties.TryGetValue("invoice", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "invoice"); } + init { JsonModel.Set(this._rawData, "invoice", value); } } /// - /// The original value of the customer's balance prior to the transaction, in the - /// customer's currency. + /// The original value of the customer's balance prior to the transaction, in + /// the customer's currency. /// public required string StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("starting_balance"); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } - public required BalanceTransactionCreateResponseProperties::Type Type + public required ApiEnum Type { get { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "type", value); } } + /// public override void Validate() { _ = this.ID; @@ -204,18 +127,211 @@ public override void Validate() public BalanceTransactionCreateResponse() { } + public BalanceTransactionCreateResponse( + BalanceTransactionCreateResponse balanceTransactionCreateResponse + ) + : base(balanceTransactionCreateResponse) { } + + public BalanceTransactionCreateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BalanceTransactionCreateResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BalanceTransactionCreateResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BalanceTransactionCreateResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BalanceTransactionCreateResponseFromRaw : IFromRawJson +{ + /// + public BalanceTransactionCreateResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BalanceTransactionCreateResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Customers.BalanceTransactions.ActionConverter))] +public enum Action +{ + AppliedToInvoice, + ManualAdjustment, + ProratedRefund, + RevertProratedRefund, + ReturnFromVoiding, + CreditNoteApplied, + CreditNoteVoided, + OverpaymentRefund, + ExternalPayment, + SmallInvoiceCarryover, +} + +sealed class ActionConverter + : JsonConverter +{ + public override global::Orb.Models.Customers.BalanceTransactions.Action Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "applied_to_invoice" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .AppliedToInvoice, + "manual_adjustment" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .ManualAdjustment, + "prorated_refund" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .ProratedRefund, + "revert_prorated_refund" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .RevertProratedRefund, + "return_from_voiding" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .ReturnFromVoiding, + "credit_note_applied" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .CreditNoteApplied, + "credit_note_voided" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .CreditNoteVoided, + "overpayment_refund" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .OverpaymentRefund, + "external_payment" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .ExternalPayment, + "small_invoice_carryover" => global::Orb + .Models + .Customers + .BalanceTransactions + .Action + .SmallInvoiceCarryover, + _ => (global::Orb.Models.Customers.BalanceTransactions.Action)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.BalanceTransactions.Action value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.BalanceTransactions.Action.AppliedToInvoice => + "applied_to_invoice", + global::Orb.Models.Customers.BalanceTransactions.Action.ManualAdjustment => + "manual_adjustment", + global::Orb.Models.Customers.BalanceTransactions.Action.ProratedRefund => + "prorated_refund", + global::Orb.Models.Customers.BalanceTransactions.Action.RevertProratedRefund => + "revert_prorated_refund", + global::Orb.Models.Customers.BalanceTransactions.Action.ReturnFromVoiding => + "return_from_voiding", + global::Orb.Models.Customers.BalanceTransactions.Action.CreditNoteApplied => + "credit_note_applied", + global::Orb.Models.Customers.BalanceTransactions.Action.CreditNoteVoided => + "credit_note_voided", + global::Orb.Models.Customers.BalanceTransactions.Action.OverpaymentRefund => + "overpayment_refund", + global::Orb.Models.Customers.BalanceTransactions.Action.ExternalPayment => + "external_payment", + global::Orb.Models.Customers.BalanceTransactions.Action.SmallInvoiceCarryover => + "small_invoice_carryover", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(BalanceTransactionCreateResponseTypeConverter))] +public enum BalanceTransactionCreateResponseType +{ + Increment, + Decrement, +} + +sealed class BalanceTransactionCreateResponseTypeConverter + : JsonConverter +{ + public override BalanceTransactionCreateResponseType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => BalanceTransactionCreateResponseType.Increment, + "decrement" => BalanceTransactionCreateResponseType.Decrement, + _ => (BalanceTransactionCreateResponseType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BalanceTransactionCreateResponseType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + BalanceTransactionCreateResponseType.Increment => "increment", + BalanceTransactionCreateResponseType.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseProperties/Action.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseProperties/Action.cs deleted file mode 100644 index 7be92ea2..00000000 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseProperties/Action.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.BalanceTransactions.BalanceTransactionCreateResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Action(string value) : Orb::IEnum -{ - public static readonly Action AppliedToInvoice = new("applied_to_invoice"); - - public static readonly Action ManualAdjustment = new("manual_adjustment"); - - public static readonly Action ProratedRefund = new("prorated_refund"); - - public static readonly Action RevertProratedRefund = new("revert_prorated_refund"); - - public static readonly Action ReturnFromVoiding = new("return_from_voiding"); - - public static readonly Action CreditNoteApplied = new("credit_note_applied"); - - public static readonly Action CreditNoteVoided = new("credit_note_voided"); - - public static readonly Action OverpaymentRefund = new("overpayment_refund"); - - public static readonly Action ExternalPayment = new("external_payment"); - - readonly string _value = value; - - public enum Value - { - AppliedToInvoice, - ManualAdjustment, - ProratedRefund, - RevertProratedRefund, - ReturnFromVoiding, - CreditNoteApplied, - CreditNoteVoided, - OverpaymentRefund, - ExternalPayment, - } - - public Value Known() => - _value switch - { - "applied_to_invoice" => Value.AppliedToInvoice, - "manual_adjustment" => Value.ManualAdjustment, - "prorated_refund" => Value.ProratedRefund, - "revert_prorated_refund" => Value.RevertProratedRefund, - "return_from_voiding" => Value.ReturnFromVoiding, - "credit_note_applied" => Value.CreditNoteApplied, - "credit_note_voided" => Value.CreditNoteVoided, - "overpayment_refund" => Value.OverpaymentRefund, - "external_payment" => Value.ExternalPayment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Action FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseProperties/Type.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseProperties/Type.cs deleted file mode 100644 index 4d6d9d4d..00000000 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionCreateResponseProperties/Type.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.BalanceTransactions.BalanceTransactionCreateResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Increment = new("increment"); - - public static readonly Type Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPage.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPage.cs new file mode 100644 index 00000000..c729c7d6 --- /dev/null +++ b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPage.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers; + +namespace Orb.Models.Customers.BalanceTransactions; + +public sealed class BalanceTransactionListPage( + IBalanceTransactionService service, + BalanceTransactionListParams parameters, + BalanceTransactionListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next( + CancellationToken cancellationToken = default + ) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponse.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponse.cs index 02d11c72..d8df659c 100644 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponse.cs +++ b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponse.cs @@ -1,52 +1,45 @@ -using BalanceTransactionListPageResponseProperties = Orb.Models.Customers.BalanceTransactions.BalanceTransactionListPageResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.BalanceTransactions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BalanceTransactionListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + BalanceTransactionListPageResponse, + BalanceTransactionListPageResponseFromRaw + >) +)] +public sealed record class BalanceTransactionListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +51,37 @@ public override void Validate() public BalanceTransactionListPageResponse() { } + public BalanceTransactionListPageResponse( + BalanceTransactionListPageResponse balanceTransactionListPageResponse + ) + : base(balanceTransactionListPageResponse) { } + + public BalanceTransactionListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BalanceTransactionListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BalanceTransactionListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BalanceTransactionListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class BalanceTransactionListPageResponseFromRaw : IFromRawJson +{ + /// + public BalanceTransactionListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BalanceTransactionListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/Data.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/Data.cs deleted file mode 100644 index 33caeeed..00000000 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/Data.cs +++ /dev/null @@ -1,215 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Customers.BalanceTransactions.BalanceTransactionListPageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.BalanceTransactions.BalanceTransactionListPageResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A unique id for this transaction. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DataProperties::Action Action - { - get - { - if (!this.Properties.TryGetValue("action", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "action", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("action"); - } - set { this.Properties["action"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The value of the amount changed in the transaction. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The creation time of this transaction. - /// - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::CreditNoteTiny? CreditNote - { - get - { - if (!this.Properties.TryGetValue("credit_note", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["credit_note"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional description provided for manual customer balance adjustments. - /// - public required string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The new value of the customer's balance prior to the transaction, in the customer's currency. - /// - public required string EndingBalance - { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("ending_balance"); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::InvoiceTiny? Invoice - { - get - { - if (!this.Properties.TryGetValue("invoice", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The original value of the customer's balance prior to the transaction, in the - /// customer's currency. - /// - public required string StartingBalance - { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("starting_balance"); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required DataProperties::Type Type - { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - this.Action.Validate(); - _ = this.Amount; - _ = this.CreatedAt; - this.CreditNote?.Validate(); - _ = this.Description; - _ = this.EndingBalance; - this.Invoice?.Validate(); - _ = this.StartingBalance; - this.Type.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/DataProperties/Action.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/DataProperties/Action.cs deleted file mode 100644 index 6442f1cc..00000000 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/DataProperties/Action.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.BalanceTransactions.BalanceTransactionListPageResponseProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Action(string value) : Orb::IEnum -{ - public static readonly Action AppliedToInvoice = new("applied_to_invoice"); - - public static readonly Action ManualAdjustment = new("manual_adjustment"); - - public static readonly Action ProratedRefund = new("prorated_refund"); - - public static readonly Action RevertProratedRefund = new("revert_prorated_refund"); - - public static readonly Action ReturnFromVoiding = new("return_from_voiding"); - - public static readonly Action CreditNoteApplied = new("credit_note_applied"); - - public static readonly Action CreditNoteVoided = new("credit_note_voided"); - - public static readonly Action OverpaymentRefund = new("overpayment_refund"); - - public static readonly Action ExternalPayment = new("external_payment"); - - readonly string _value = value; - - public enum Value - { - AppliedToInvoice, - ManualAdjustment, - ProratedRefund, - RevertProratedRefund, - ReturnFromVoiding, - CreditNoteApplied, - CreditNoteVoided, - OverpaymentRefund, - ExternalPayment, - } - - public Value Known() => - _value switch - { - "applied_to_invoice" => Value.AppliedToInvoice, - "manual_adjustment" => Value.ManualAdjustment, - "prorated_refund" => Value.ProratedRefund, - "revert_prorated_refund" => Value.RevertProratedRefund, - "return_from_voiding" => Value.ReturnFromVoiding, - "credit_note_applied" => Value.CreditNoteApplied, - "credit_note_voided" => Value.CreditNoteVoided, - "overpayment_refund" => Value.OverpaymentRefund, - "external_payment" => Value.ExternalPayment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Action FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/DataProperties/Type.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/DataProperties/Type.cs deleted file mode 100644 index 375f5d8b..00000000 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListPageResponseProperties/DataProperties/Type.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.BalanceTransactions.BalanceTransactionListPageResponseProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Increment = new("increment"); - - public static readonly Type Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListParams.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListParams.cs index 00854cf7..119e725f 100644 --- a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListParams.cs +++ b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListParams.cs @@ -1,35 +1,37 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.BalanceTransactions; /// /// ## The customer balance /// -/// The customer balance is an amount in the customer's currency, which Orb automatically -/// applies to subsequent invoices. This balance can be adjusted manually via Orb's -/// webapp on the customer details page. You can use this balance to provide a fixed -/// mid-period credit to the customer. Commonly, this is done due to system downtime/SLA -/// violation, or an adhoc adjustment discussed with the customer. +/// The customer balance is an amount in the customer's currency, which Orb +/// automatically applies to subsequent invoices. This balance can be adjusted manually +/// via Orb's webapp on the customer details page. You can use this balance to provide +/// a fixed mid-period credit to the customer. Commonly, this is done due to system +/// downtime/SLA violation, or an adhoc adjustment discussed with the customer. /// -/// If the balance is a positive value at the time of invoicing, it represents that -/// the customer has credit that should be used to offset the amount due on the next -/// issued invoice. In this case, Orb will automatically reduce the next invoice -/// by the balance amount, and roll over any remaining balance if the invoice is -/// fully discounted. +/// If the balance is a positive value at the time of invoicing, it represents +/// that the customer has credit that should be used to offset the amount due on the +/// next issued invoice. In this case, Orb will automatically reduce the next invoice +/// by the balance amount, and roll over any remaining balance if the invoice is fully discounted. /// -/// If the balance is a negative value at the time of invoicing, Orb will increase -/// the invoice's amount due with a positive adjustment, and reset the balance to 0. +/// If the balance is a negative value at the time of invoicing, Orb will increase +/// the invoice's amount due with a positive adjustment, and reset the balance to 0. /// -/// This endpoint retrieves all customer balance transactions in reverse chronological +/// This endpoint retrieves all customer balance transactions in reverse chronological /// order for a single customer, providing a complete audit trail of all adjustments -/// and invoice applications. +/// and invoice applications. /// -public sealed record class BalanceTransactionListParams : Orb::ParamsBase +public sealed record class BalanceTransactionListParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -37,14 +39,8 @@ public sealed record class BalanceTransactionListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -52,121 +48,121 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public System::DateTime? OperationTimeGt + public DateTimeOffset? OperationTimeGt { get { - if ( - !this.QueryProperties.TryGetValue( - "operation_time[gt]", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["operation_time[gt]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "operation_time[gt]" ); } + init { JsonModel.Set(this._rawQueryData, "operation_time[gt]", value); } } - public System::DateTime? OperationTimeGte + public DateTimeOffset? OperationTimeGte { get { - if ( - !this.QueryProperties.TryGetValue( - "operation_time[gte]", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["operation_time[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "operation_time[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "operation_time[gte]", value); } } - public System::DateTime? OperationTimeLt + public DateTimeOffset? OperationTimeLt { get { - if ( - !this.QueryProperties.TryGetValue( - "operation_time[lt]", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["operation_time[lt]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "operation_time[lt]" ); } + init { JsonModel.Set(this._rawQueryData, "operation_time[lt]", value); } } - public System::DateTime? OperationTimeLte + public DateTimeOffset? OperationTimeLte { get { - if ( - !this.QueryProperties.TryGetValue( - "operation_time[lte]", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["operation_time[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "operation_time[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "operation_time[lte]", value); } + } + + public BalanceTransactionListParams() { } + + public BalanceTransactionListParams(BalanceTransactionListParams balanceTransactionListParams) + : base(balanceTransactionListParams) { } + + public BalanceTransactionListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BalanceTransactionListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static BalanceTransactionListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/balance_transactions", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListResponse.cs b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListResponse.cs new file mode 100644 index 00000000..ab48f431 --- /dev/null +++ b/src/Orb/Models/Customers/BalanceTransactions/BalanceTransactionListResponse.cs @@ -0,0 +1,280 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.BalanceTransactions; + +[JsonConverter( + typeof(JsonModelConverter< + BalanceTransactionListResponse, + BalanceTransactionListResponseFromRaw + >) +)] +public sealed record class BalanceTransactionListResponse : JsonModel +{ + /// + /// A unique id for this transaction. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required ApiEnum Action + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "action" + ); + } + init { JsonModel.Set(this._rawData, "action", value); } + } + + /// + /// The value of the amount changed in the transaction. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The creation time of this transaction. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required CreditNoteTiny? CreditNote + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_note"); } + init { JsonModel.Set(this._rawData, "credit_note", value); } + } + + /// + /// An optional description provided for manual customer balance adjustments. + /// + public required string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// The new value of the customer's balance prior to the transaction, in the customer's currency. + /// + public required string EndingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } + } + + public required InvoiceTiny? Invoice + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice"); } + init { JsonModel.Set(this._rawData, "invoice", value); } + } + + /// + /// The original value of the customer's balance prior to the transaction, in + /// the customer's currency. + /// + public required string StartingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } + } + + public required ApiEnum Type + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); + } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.Action.Validate(); + _ = this.Amount; + _ = this.CreatedAt; + this.CreditNote?.Validate(); + _ = this.Description; + _ = this.EndingBalance; + this.Invoice?.Validate(); + _ = this.StartingBalance; + this.Type.Validate(); + } + + public BalanceTransactionListResponse() { } + + public BalanceTransactionListResponse( + BalanceTransactionListResponse balanceTransactionListResponse + ) + : base(balanceTransactionListResponse) { } + + public BalanceTransactionListResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BalanceTransactionListResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BalanceTransactionListResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BalanceTransactionListResponseFromRaw : IFromRawJson +{ + /// + public BalanceTransactionListResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BalanceTransactionListResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BalanceTransactionListResponseActionConverter))] +public enum BalanceTransactionListResponseAction +{ + AppliedToInvoice, + ManualAdjustment, + ProratedRefund, + RevertProratedRefund, + ReturnFromVoiding, + CreditNoteApplied, + CreditNoteVoided, + OverpaymentRefund, + ExternalPayment, + SmallInvoiceCarryover, +} + +sealed class BalanceTransactionListResponseActionConverter + : JsonConverter +{ + public override BalanceTransactionListResponseAction Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "applied_to_invoice" => BalanceTransactionListResponseAction.AppliedToInvoice, + "manual_adjustment" => BalanceTransactionListResponseAction.ManualAdjustment, + "prorated_refund" => BalanceTransactionListResponseAction.ProratedRefund, + "revert_prorated_refund" => BalanceTransactionListResponseAction.RevertProratedRefund, + "return_from_voiding" => BalanceTransactionListResponseAction.ReturnFromVoiding, + "credit_note_applied" => BalanceTransactionListResponseAction.CreditNoteApplied, + "credit_note_voided" => BalanceTransactionListResponseAction.CreditNoteVoided, + "overpayment_refund" => BalanceTransactionListResponseAction.OverpaymentRefund, + "external_payment" => BalanceTransactionListResponseAction.ExternalPayment, + "small_invoice_carryover" => BalanceTransactionListResponseAction.SmallInvoiceCarryover, + _ => (BalanceTransactionListResponseAction)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BalanceTransactionListResponseAction value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BalanceTransactionListResponseAction.AppliedToInvoice => "applied_to_invoice", + BalanceTransactionListResponseAction.ManualAdjustment => "manual_adjustment", + BalanceTransactionListResponseAction.ProratedRefund => "prorated_refund", + BalanceTransactionListResponseAction.RevertProratedRefund => + "revert_prorated_refund", + BalanceTransactionListResponseAction.ReturnFromVoiding => "return_from_voiding", + BalanceTransactionListResponseAction.CreditNoteApplied => "credit_note_applied", + BalanceTransactionListResponseAction.CreditNoteVoided => "credit_note_voided", + BalanceTransactionListResponseAction.OverpaymentRefund => "overpayment_refund", + BalanceTransactionListResponseAction.ExternalPayment => "external_payment", + BalanceTransactionListResponseAction.SmallInvoiceCarryover => + "small_invoice_carryover", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(BalanceTransactionListResponseTypeConverter))] +public enum BalanceTransactionListResponseType +{ + Increment, + Decrement, +} + +sealed class BalanceTransactionListResponseTypeConverter + : JsonConverter +{ + public override BalanceTransactionListResponseType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => BalanceTransactionListResponseType.Increment, + "decrement" => BalanceTransactionListResponseType.Decrement, + _ => (BalanceTransactionListResponseType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BalanceTransactionListResponseType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BalanceTransactionListResponseType.Increment => "increment", + BalanceTransactionListResponseType.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Costs/CostListByExternalIDParams.cs b/src/Orb/Models/Customers/Costs/CostListByExternalIDParams.cs index 9f24c587..849a1dc3 100644 --- a/src/Orb/Models/Customers/Costs/CostListByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Costs/CostListByExternalIDParams.cs @@ -1,203 +1,280 @@ -using CostListByExternalIDParamsProperties = Orb.Models.Customers.Costs.CostListByExternalIDParamsProperties; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Costs; /// /// This endpoint is used to fetch a day-by-day snapshot of a customer's costs in -/// Orb, calculated by applying pricing information to the underlying usage (see -/// the [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) +/// Orb, calculated by applying pricing information to the underlying usage (see the +/// [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) /// to fetch usage per metric, in usage units rather than a currency). /// -/// This endpoint can be leveraged for internal tooling and to provide a more transparent -/// billing experience for your end users: +/// This endpoint can be leveraged for internal tooling and to provide a more +/// transparent billing experience for your end users: /// -/// 1. Understand the cost breakdown per line item historically and in real-time for -/// the current billing period. 2. Provide customer visibility into how different -/// services are contributing to the overall invoice with a per-day timeseries -/// (as compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) +/// 1. Understand the cost breakdown per line item historically and in real-time +/// for the current billing period. 2. Provide customer visibility into how different +/// services are contributing to the overall invoice with a per-day timeseries (as +/// compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) /// resource, which represents a snapshot for the current period). 3. Assess how -/// minimums and discounts affect your customers by teasing apart costs directly as -/// a result of usage, as opposed to minimums and discounts at the plan and price -/// level. 4. Gain insight into key customer health metrics, such as the percent -/// utilization of the minimum committed spend. +/// minimums and discounts affect your customers by teasing apart costs directly +/// as a result of usage, as opposed to minimums and discounts at the plan and price +/// level. 4. Gain insight into key customer health metrics, such as the percent utilization +/// of the minimum committed spend. /// -/// ## Fetching subscriptions By default, this endpoint fetches the currently active -/// subscription for the customer, and returns cost information for the subscription's +/// ## Fetching subscriptions By default, this endpoint fetches the currently +/// active subscription for the customer, and returns cost information for the subscription's /// current billing period, broken down by each participating price. If there are /// no currently active subscriptions, this will instead default to the most recently /// active subscription or return an empty series if none are found. For example, /// if your plan charges for compute hours, job runs, and data syncs, then this endpoint -/// would provide a daily breakdown of your customer's cost for each of those axes. +/// would provide a daily breakdown of your customer's cost for each of those axes. /// -/// If timeframe bounds are specified, Orb fetches all subscriptions that were active -/// in that timeframe. If two subscriptions overlap on a single day, costs from each -/// price will be summed, and prices for both subscriptions will be included in the breakdown. +/// If timeframe bounds are specified, Orb fetches all subscriptions that were +/// active in that timeframe. If two subscriptions overlap on a single day, costs +/// from each price will be summed, and prices for both subscriptions will be included +/// in the breakdown. /// -/// ## Prepaid plans For plans that include prices which deduct credits rather than -/// accrue in-arrears charges in a billable currency, this endpoint will return the -/// total deduction amount, in credits, for the specified timeframe. +/// ## Prepaid plans For plans that include prices which deduct credits rather +/// than accrue in-arrears charges in a billable currency, this endpoint will return +/// the total deduction amount, in credits, for the specified timeframe. /// -/// ## Cumulative subtotals and totals Since the subtotal and total must factor in -/// any billing-period level discounts and minimums, it's most meaningful to consider +/// ## Cumulative subtotals and totals Since the subtotal and total must factor +/// in any billing-period level discounts and minimums, it's most meaningful to consider /// costs relative to the start of the subscription's billing period. As a result, /// by default this endpoint returns cumulative totals since the beginning of the -/// billing period. In particular, the `timeframe_start` of a returned timeframe -/// window is *always* the beginning of the billing period and `timeframe_end` is -/// incremented one day at a time to build the result. +/// billing period. In particular, the `timeframe_start` of a returned timeframe window +/// is *always* the beginning of the billing period and `timeframe_end` is incremented +/// one day at a time to build the result. /// -/// A customer that uses a few API calls a day but has a minimum commitment might -/// exhibit the following pattern for their subtotal and total in the first few days -/// of the month. Here, we assume that each API call is \$2.50, the customer's plan -/// has a monthly minimum of \$50 for this price, and that the subscription's billing -/// period bounds are aligned to the first of the month: +/// A customer that uses a few API calls a day but has a minimum commitment +/// might exhibit the following pattern for their subtotal and total in the first +/// few days of the month. Here, we assume that each API call is \$2.50, the customer's +/// plan has a monthly minimum of \$50 for this price, and that the subscription's +/// billing period bounds are aligned to the first of the month: /// -/// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. -/// commitment) | | -----------| ----------- | ----------- | ----------- |----------- +/// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total +/// (incl. commitment) | | -----------| ----------- | ----------- | ----------- |----------- /// | | 2023-02-01 | 2023-02-02 | 9 | \$22.50 | \$50.00 | | 2023-02-01 | 2023-02-03 /// | 19 | \$47.50 | \$50.00 | | 2023-02-01 | 2023-02-04 | 20 | \$50.00 | \$50.00 /// | | 2023-02-01 | 2023-02-05 | 28 | \$70.00 | \$70.00 | | 2023-02-01 | 2023-02-06 -/// | 36 | \$90.00 | \$90.00 | +/// | 36 | \$90.00 | \$90.00 | /// -/// ### Periodic values When the query parameter `view_mode=periodic` is specified, -/// Orb will return an incremental day-by-day view of costs. In this case, there -/// will always be a one-day difference between `timeframe_start` and `timeframe_end` -/// for the timeframes returned. This is a transform on top of the cumulative costs, -/// calculated by taking the difference of each timeframe with the last. Note that -/// in the above example, the `Total` value would be 0 for the second two data points, -/// since the minimum commitment has not yet been hit and each day is not contributing -/// anything to the total cost. +/// ### Periodic values When the query parameter `view_mode=periodic` is specified, +/// Orb will return an incremental day-by-day view of costs. In this case, there will +/// always be a one-day difference between `timeframe_start` and `timeframe_end` for +/// the timeframes returned. This is a transform on top of the cumulative costs, calculated +/// by taking the difference of each timeframe with the last. Note that in the above +/// example, the `Total` value would be 0 for the second two data points, since the +/// minimum commitment has not yet been hit and each day is not contributing anything +/// to the total cost. /// -/// ## Timeframe bounds For an active subscription, both timeframes should be specified -/// in the request. If a subscription starts or ends within the timeframe, the response -/// will only include windows where the subscription is active. If a subscription -/// has ended, no timeframe bounds need to be specified and the response will default -/// to the billing period when the subscription was last active. +/// ## Timeframe bounds For an active subscription, both timeframes should +/// be specified in the request. If a subscription starts or ends within the timeframe, +/// the response will only include windows where the subscription is active. If a +/// subscription has ended, no timeframe bounds need to be specified and the response +/// will default to the billing period when the subscription was last active. /// -/// As noted above, `timeframe_start` for a given cumulative datapoint is always +/// As noted above, `timeframe_start` for a given cumulative datapoint is always /// the beginning of the billing period, and `timeframe_end` is incremented one day /// at a time to construct the response. When a timeframe is passed in that is not /// aligned to the current subscription's billing period, the response will contain -/// cumulative totals from multiple billing periods. +/// cumulative totals from multiple billing periods. /// -/// Suppose the queried customer has a subscription aligned to the 15th of every -/// month. If this endpoint is queried with the date range `2023-06-01` - `2023-07-01`, +/// Suppose the queried customer has a subscription aligned to the 15th of +/// every month. If this endpoint is queried with the date range `2023-06-01` - `2023-07-01`, /// the first data point will represent about half a billing period's worth of costs, /// accounting for accruals from the start of the billing period and inclusive of /// the first day of the timeframe (`timeframe_start = 2023-05-15 00:00:00`, `timeframe_end -/// = 2023-06-02 00:00:00`) +/// = 2023-06-02 00:00:00`) /// -/// | datapoint index | timeframe_start | timeframe_end | | ----------- | -----------| +/// | datapoint index | timeframe_start | timeframe_end | | ----------- | -----------| /// ----------- | | 0 | 2023-05-15 | 2023-06-02 | | 1 | 2023-05-15 | 2023-06-03 | /// | 2 | ... | ... | | 3 | 2023-05-15 | 2023-06-14 | | 4 | 2023-06-15 | 2023-06-16 -/// | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 | 2023-07-01 | +/// | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 | 2023-07-01 | /// -/// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). +/// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). /// -/// ### Matrix prices When a price uses matrix pricing, it's important to view costs -/// grouped by those matrix dimensions. Orb will return `price_groups` with the `grouping_key` -/// and `secondary_grouping_key` based on the matrix price definition, for each `grouping_value` -/// and `secondary_grouping_value` available. +/// ### Matrix prices When a price uses matrix pricing, it's important to view +/// costs grouped by those matrix dimensions. Orb will return `price_groups` with +/// the `grouping_key` and `secondary_grouping_key` based on the matrix price definition, +/// for each `grouping_value` and `secondary_grouping_value` available. /// -public sealed record class CostListByExternalIDParams : Orb::ParamsBase +public sealed record class CostListByExternalIDParams : ParamsBase { - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } /// /// The currency or custom pricing unit to use. /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// /// Costs returned are exclusive of `timeframe_end`. /// - public System::DateTime? TimeframeEnd + public System::DateTimeOffset? TimeframeEnd { get { - if (!this.QueryProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_end" + ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_end", value); } } /// /// Costs returned are inclusive of `timeframe_start`. /// - public System::DateTime? TimeframeStart + public System::DateTimeOffset? TimeframeStart { get { - if (!this.QueryProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_start" ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_start", value); } } /// /// Controls whether Orb returns cumulative costs since the start of the billing - /// period, or incremental day-by-day costs. If your customer has minimums or discounts, - /// it's strongly recommended that you use the default cumulative behavior. + /// period, or incremental day-by-day costs. If your customer has minimums or + /// discounts, it's strongly recommended that you use the default cumulative behavior. /// - public CostListByExternalIDParamsProperties::ViewMode? ViewMode + public ApiEnum? ViewMode { get { - if (!this.QueryProperties.TryGetValue("view_mode", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawQueryData, + "view_mode" ); } - set { this.QueryProperties["view_mode"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "view_mode", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public CostListByExternalIDParams() { } + + public CostListByExternalIDParams(CostListByExternalIDParams costListByExternalIDParams) + : base(costListByExternalIDParams) { } + + public CostListByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CostListByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CostListByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/costs", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// Controls whether Orb returns cumulative costs since the start of the billing +/// period, or incremental day-by-day costs. If your customer has minimums or discounts, +/// it's strongly recommended that you use the default cumulative behavior. +/// +[JsonConverter(typeof(CostListByExternalIDParamsViewModeConverter))] +public enum CostListByExternalIDParamsViewMode +{ + Periodic, + Cumulative, +} + +sealed class CostListByExternalIDParamsViewModeConverter + : JsonConverter +{ + public override CostListByExternalIDParamsViewMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "periodic" => CostListByExternalIDParamsViewMode.Periodic, + "cumulative" => CostListByExternalIDParamsViewMode.Cumulative, + _ => (CostListByExternalIDParamsViewMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CostListByExternalIDParamsViewMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CostListByExternalIDParamsViewMode.Periodic => "periodic", + CostListByExternalIDParamsViewMode.Cumulative => "cumulative", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Costs/CostListByExternalIDParamsProperties/ViewMode.cs b/src/Orb/Models/Customers/Costs/CostListByExternalIDParamsProperties/ViewMode.cs deleted file mode 100644 index 6c946f90..00000000 --- a/src/Orb/Models/Customers/Costs/CostListByExternalIDParamsProperties/ViewMode.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Costs.CostListByExternalIDParamsProperties; - -/// -/// Controls whether Orb returns cumulative costs since the start of the billing period, -/// or incremental day-by-day costs. If your customer has minimums or discounts, it's -/// strongly recommended that you use the default cumulative behavior. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ViewMode(string value) : Orb::IEnum -{ - public static readonly ViewMode Periodic = new("periodic"); - - public static readonly ViewMode Cumulative = new("cumulative"); - - readonly string _value = value; - - public enum Value - { - Periodic, - Cumulative, - } - - public Value Known() => - _value switch - { - "periodic" => Value.Periodic, - "cumulative" => Value.Cumulative, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ViewMode FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Costs/CostListByExternalIDResponse.cs b/src/Orb/Models/Customers/Costs/CostListByExternalIDResponse.cs index 1063ef50..62ebd09e 100644 --- a/src/Orb/Models/Customers/Costs/CostListByExternalIDResponse.cs +++ b/src/Orb/Models/Customers/Costs/CostListByExternalIDResponse.cs @@ -1,31 +1,24 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Costs; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CostListByExternalIDResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CostListByExternalIDResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -36,18 +29,42 @@ public override void Validate() public CostListByExternalIDResponse() { } + public CostListByExternalIDResponse(CostListByExternalIDResponse costListByExternalIDResponse) + : base(costListByExternalIDResponse) { } + + public CostListByExternalIDResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CostListByExternalIDResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CostListByExternalIDResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CostListByExternalIDResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public CostListByExternalIDResponse(List data) + : this() + { + this.Data = data; + } +} + +class CostListByExternalIDResponseFromRaw : IFromRawJson +{ + /// + public CostListByExternalIDResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CostListByExternalIDResponse.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Customers/Costs/CostListParams.cs b/src/Orb/Models/Customers/Costs/CostListParams.cs index 34e1dbda..37699c04 100644 --- a/src/Orb/Models/Customers/Costs/CostListParams.cs +++ b/src/Orb/Models/Customers/Costs/CostListParams.cs @@ -1,198 +1,272 @@ -using CostListParamsProperties = Orb.Models.Customers.Costs.CostListParamsProperties; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Costs; /// /// This endpoint is used to fetch a day-by-day snapshot of a customer's costs in -/// Orb, calculated by applying pricing information to the underlying usage (see -/// the [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) +/// Orb, calculated by applying pricing information to the underlying usage (see the +/// [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) /// to fetch usage per metric, in usage units rather than a currency). /// -/// This endpoint can be leveraged for internal tooling and to provide a more transparent -/// billing experience for your end users: +/// This endpoint can be leveraged for internal tooling and to provide a more +/// transparent billing experience for your end users: /// -/// 1. Understand the cost breakdown per line item historically and in real-time for -/// the current billing period. 2. Provide customer visibility into how different -/// services are contributing to the overall invoice with a per-day timeseries -/// (as compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) +/// 1. Understand the cost breakdown per line item historically and in real-time +/// for the current billing period. 2. Provide customer visibility into how different +/// services are contributing to the overall invoice with a per-day timeseries (as +/// compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) /// resource, which represents a snapshot for the current period). 3. Assess how -/// minimums and discounts affect your customers by teasing apart costs directly as -/// a result of usage, as opposed to minimums and discounts at the plan and price -/// level. 4. Gain insight into key customer health metrics, such as the percent -/// utilization of the minimum committed spend. +/// minimums and discounts affect your customers by teasing apart costs directly +/// as a result of usage, as opposed to minimums and discounts at the plan and price +/// level. 4. Gain insight into key customer health metrics, such as the percent utilization +/// of the minimum committed spend. /// -/// ## Fetching subscriptions By default, this endpoint fetches the currently active -/// subscription for the customer, and returns cost information for the subscription's +/// ## Fetching subscriptions By default, this endpoint fetches the currently +/// active subscription for the customer, and returns cost information for the subscription's /// current billing period, broken down by each participating price. If there are /// no currently active subscriptions, this will instead default to the most recently /// active subscription or return an empty series if none are found. For example, /// if your plan charges for compute hours, job runs, and data syncs, then this endpoint -/// would provide a daily breakdown of your customer's cost for each of those axes. +/// would provide a daily breakdown of your customer's cost for each of those axes. /// -/// If timeframe bounds are specified, Orb fetches all subscriptions that were active -/// in that timeframe. If two subscriptions overlap on a single day, costs from each -/// price will be summed, and prices for both subscriptions will be included in the breakdown. +/// If timeframe bounds are specified, Orb fetches all subscriptions that were +/// active in that timeframe. If two subscriptions overlap on a single day, costs +/// from each price will be summed, and prices for both subscriptions will be included +/// in the breakdown. /// -/// ## Prepaid plans For plans that include prices which deduct credits rather than -/// accrue in-arrears charges in a billable currency, this endpoint will return the -/// total deduction amount, in credits, for the specified timeframe. +/// ## Prepaid plans For plans that include prices which deduct credits rather +/// than accrue in-arrears charges in a billable currency, this endpoint will return +/// the total deduction amount, in credits, for the specified timeframe. /// -/// ## Cumulative subtotals and totals Since the subtotal and total must factor in -/// any billing-period level discounts and minimums, it's most meaningful to consider +/// ## Cumulative subtotals and totals Since the subtotal and total must factor +/// in any billing-period level discounts and minimums, it's most meaningful to consider /// costs relative to the start of the subscription's billing period. As a result, /// by default this endpoint returns cumulative totals since the beginning of the -/// billing period. In particular, the `timeframe_start` of a returned timeframe -/// window is *always* the beginning of the billing period and `timeframe_end` is -/// incremented one day at a time to build the result. +/// billing period. In particular, the `timeframe_start` of a returned timeframe window +/// is *always* the beginning of the billing period and `timeframe_end` is incremented +/// one day at a time to build the result. /// -/// A customer that uses a few API calls a day but has a minimum commitment might -/// exhibit the following pattern for their subtotal and total in the first few days -/// of the month. Here, we assume that each API call is \$2.50, the customer's plan -/// has a monthly minimum of \$50 for this price, and that the subscription's billing -/// period bounds are aligned to the first of the month: +/// A customer that uses a few API calls a day but has a minimum commitment +/// might exhibit the following pattern for their subtotal and total in the first +/// few days of the month. Here, we assume that each API call is \$2.50, the customer's +/// plan has a monthly minimum of \$50 for this price, and that the subscription's +/// billing period bounds are aligned to the first of the month: /// -/// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. -/// commitment) | | -----------| ----------- | ----------- | ----------- |----------- +/// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total +/// (incl. commitment) | | -----------| ----------- | ----------- | ----------- |----------- /// | | 2023-02-01 | 2023-02-02 | 9 | \$22.50 | \$50.00 | | 2023-02-01 | 2023-02-03 /// | 19 | \$47.50 | \$50.00 | | 2023-02-01 | 2023-02-04 | 20 | \$50.00 | \$50.00 /// | | 2023-02-01 | 2023-02-05 | 28 | \$70.00 | \$70.00 | | 2023-02-01 | 2023-02-06 -/// | 36 | \$90.00 | \$90.00 | +/// | 36 | \$90.00 | \$90.00 | /// -/// ### Periodic values When the query parameter `view_mode=periodic` is specified, -/// Orb will return an incremental day-by-day view of costs. In this case, there -/// will always be a one-day difference between `timeframe_start` and `timeframe_end` -/// for the timeframes returned. This is a transform on top of the cumulative costs, -/// calculated by taking the difference of each timeframe with the last. Note that -/// in the above example, the `Total` value would be 0 for the second two data points, -/// since the minimum commitment has not yet been hit and each day is not contributing -/// anything to the total cost. +/// ### Periodic values When the query parameter `view_mode=periodic` is specified, +/// Orb will return an incremental day-by-day view of costs. In this case, there will +/// always be a one-day difference between `timeframe_start` and `timeframe_end` for +/// the timeframes returned. This is a transform on top of the cumulative costs, calculated +/// by taking the difference of each timeframe with the last. Note that in the above +/// example, the `Total` value would be 0 for the second two data points, since the +/// minimum commitment has not yet been hit and each day is not contributing anything +/// to the total cost. /// -/// ## Timeframe bounds For an active subscription, both timeframes should be specified -/// in the request. If a subscription starts or ends within the timeframe, the response -/// will only include windows where the subscription is active. If a subscription -/// has ended, no timeframe bounds need to be specified and the response will default -/// to the billing period when the subscription was last active. +/// ## Timeframe bounds For an active subscription, both timeframes should +/// be specified in the request. If a subscription starts or ends within the timeframe, +/// the response will only include windows where the subscription is active. If a +/// subscription has ended, no timeframe bounds need to be specified and the response +/// will default to the billing period when the subscription was last active. /// -/// As noted above, `timeframe_start` for a given cumulative datapoint is always +/// As noted above, `timeframe_start` for a given cumulative datapoint is always /// the beginning of the billing period, and `timeframe_end` is incremented one day /// at a time to construct the response. When a timeframe is passed in that is not /// aligned to the current subscription's billing period, the response will contain -/// cumulative totals from multiple billing periods. +/// cumulative totals from multiple billing periods. /// -/// Suppose the queried customer has a subscription aligned to the 15th of every -/// month. If this endpoint is queried with the date range `2023-06-01` - `2023-07-01`, +/// Suppose the queried customer has a subscription aligned to the 15th of +/// every month. If this endpoint is queried with the date range `2023-06-01` - `2023-07-01`, /// the first data point will represent about half a billing period's worth of costs, /// accounting for accruals from the start of the billing period and inclusive of /// the first day of the timeframe (`timeframe_start = 2023-05-15 00:00:00`, `timeframe_end -/// = 2023-06-02 00:00:00`) +/// = 2023-06-02 00:00:00`) /// -/// | datapoint index | timeframe_start | timeframe_end | | ----------- | -----------| +/// | datapoint index | timeframe_start | timeframe_end | | ----------- | -----------| /// ----------- | | 0 | 2023-05-15 | 2023-06-02 | | 1 | 2023-05-15 | 2023-06-03 | /// | 2 | ... | ... | | 3 | 2023-05-15 | 2023-06-14 | | 4 | 2023-06-15 | 2023-06-16 -/// | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 | 2023-07-01 | +/// | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 | 2023-07-01 | /// -/// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). +/// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). /// -/// ### Matrix prices When a price uses matrix pricing, it's important to view costs -/// grouped by those matrix dimensions. Orb will return `price_groups` with the `grouping_key` -/// and `secondary_grouping_key` based on the matrix price definition, for each `grouping_value` -/// and `secondary_grouping_value` available. +/// ### Matrix prices When a price uses matrix pricing, it's important to view +/// costs grouped by those matrix dimensions. Orb will return `price_groups` with +/// the `grouping_key` and `secondary_grouping_key` based on the matrix price definition, +/// for each `grouping_value` and `secondary_grouping_value` available. /// -public sealed record class CostListParams : Orb::ParamsBase +public sealed record class CostListParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } /// /// The currency or custom pricing unit to use. /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// /// Costs returned are exclusive of `timeframe_end`. /// - public System::DateTime? TimeframeEnd + public System::DateTimeOffset? TimeframeEnd { get { - if (!this.QueryProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_end" + ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_end", value); } } /// /// Costs returned are inclusive of `timeframe_start`. /// - public System::DateTime? TimeframeStart + public System::DateTimeOffset? TimeframeStart { get { - if (!this.QueryProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_start" ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_start", value); } } /// /// Controls whether Orb returns cumulative costs since the start of the billing - /// period, or incremental day-by-day costs. If your customer has minimums or discounts, - /// it's strongly recommended that you use the default cumulative behavior. + /// period, or incremental day-by-day costs. If your customer has minimums or + /// discounts, it's strongly recommended that you use the default cumulative behavior. /// - public CostListParamsProperties::ViewMode? ViewMode + public ApiEnum? ViewMode { get { - if (!this.QueryProperties.TryGetValue("view_mode", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawQueryData, + "view_mode" + ); } - set { this.QueryProperties["view_mode"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "view_mode", value); } + } + + public CostListParams() { } + + public CostListParams(CostListParams costListParams) + : base(costListParams) { } + + public CostListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CostListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CostListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/costs", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// Controls whether Orb returns cumulative costs since the start of the billing +/// period, or incremental day-by-day costs. If your customer has minimums or discounts, +/// it's strongly recommended that you use the default cumulative behavior. +/// +[JsonConverter(typeof(ViewModeConverter))] +public enum ViewMode +{ + Periodic, + Cumulative, +} + +sealed class ViewModeConverter : JsonConverter +{ + public override ViewMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "periodic" => ViewMode.Periodic, + "cumulative" => ViewMode.Cumulative, + _ => (ViewMode)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, ViewMode value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + ViewMode.Periodic => "periodic", + ViewMode.Cumulative => "cumulative", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Costs/CostListParamsProperties/ViewMode.cs b/src/Orb/Models/Customers/Costs/CostListParamsProperties/ViewMode.cs deleted file mode 100644 index 19d6f1b6..00000000 --- a/src/Orb/Models/Customers/Costs/CostListParamsProperties/ViewMode.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Costs.CostListParamsProperties; - -/// -/// Controls whether Orb returns cumulative costs since the start of the billing period, -/// or incremental day-by-day costs. If your customer has minimums or discounts, it's -/// strongly recommended that you use the default cumulative behavior. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ViewMode(string value) : Orb::IEnum -{ - public static readonly ViewMode Periodic = new("periodic"); - - public static readonly ViewMode Cumulative = new("cumulative"); - - readonly string _value = value; - - public enum Value - { - Periodic, - Cumulative, - } - - public Value Known() => - _value switch - { - "periodic" => Value.Periodic, - "cumulative" => Value.Cumulative, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ViewMode FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Costs/CostListResponse.cs b/src/Orb/Models/Customers/Costs/CostListResponse.cs index 3f41c245..73763f41 100644 --- a/src/Orb/Models/Customers/Costs/CostListResponse.cs +++ b/src/Orb/Models/Customers/Costs/CostListResponse.cs @@ -1,29 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Costs; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CostListResponse : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CostListResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -34,18 +27,41 @@ public override void Validate() public CostListResponse() { } + public CostListResponse(CostListResponse costListResponse) + : base(costListResponse) { } + + public CostListResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CostListResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CostListResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CostListResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public CostListResponse(List data) + : this() + { + this.Data = data; + } +} + +class CostListResponseFromRaw : IFromRawJson +{ + /// + public CostListResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + CostListResponse.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPage.cs b/src/Orb/Models/Customers/Credits/CreditListByExternalIDPage.cs new file mode 100644 index 00000000..b92e3be3 --- /dev/null +++ b/src/Orb/Models/Customers/Credits/CreditListByExternalIDPage.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers; + +namespace Orb.Models.Customers.Credits; + +public sealed class CreditListByExternalIDPage( + ICreditService service, + CreditListByExternalIDParams parameters, + CreditListByExternalIDPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next( + CancellationToken cancellationToken = default + ) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .ListByExternalID(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponse.cs b/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponse.cs index 584b3cf4..52a79c53 100644 --- a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponse.cs +++ b/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponse.cs @@ -1,52 +1,45 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CreditListByExternalIDPageResponseProperties = Orb.Models.Customers.Credits.CreditListByExternalIDPageResponseProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditListByExternalIDPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + CreditListByExternalIDPageResponse, + CreditListByExternalIDPageResponseFromRaw + >) +)] +public sealed record class CreditListByExternalIDPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +51,37 @@ public override void Validate() public CreditListByExternalIDPageResponse() { } + public CreditListByExternalIDPageResponse( + CreditListByExternalIDPageResponse creditListByExternalIDPageResponse + ) + : base(creditListByExternalIDPageResponse) { } + + public CreditListByExternalIDPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditListByExternalIDPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CreditListByExternalIDPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CreditListByExternalIDPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CreditListByExternalIDPageResponseFromRaw : IFromRawJson +{ + /// + public CreditListByExternalIDPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CreditListByExternalIDPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponseProperties/Data.cs b/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponseProperties/Data.cs deleted file mode 100644 index 4c8ef5ac..00000000 --- a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponseProperties/Data.cs +++ /dev/null @@ -1,156 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Customers.Credits.CreditListByExternalIDPageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.CreditListByExternalIDPageResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double Balance - { - get - { - if (!this.Properties.TryGetValue("balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["balance"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime? EffectiveDate - { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "effective_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime? ExpiryDate - { - get - { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? MaximumInitialBalance - { - get - { - if ( - !this.Properties.TryGetValue( - "maximum_initial_balance", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "maximum_initial_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["maximum_initial_balance"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required string? PerUnitCostBasis - { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required DataProperties::Status Status - { - get - { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); - } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Balance; - _ = this.EffectiveDate; - _ = this.ExpiryDate; - _ = this.MaximumInitialBalance; - _ = this.PerUnitCostBasis; - this.Status.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponseProperties/DataProperties/Status.cs b/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponseProperties/DataProperties/Status.cs deleted file mode 100644 index 8b58cee3..00000000 --- a/src/Orb/Models/Customers/Credits/CreditListByExternalIDPageResponseProperties/DataProperties/Status.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.CreditListByExternalIDPageResponseProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status PendingPayment = new("pending_payment"); - - readonly string _value = value; - - public enum Value - { - Active, - PendingPayment, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "pending_payment" => Value.PendingPayment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/CreditListByExternalIDParams.cs b/src/Orb/Models/Customers/Credits/CreditListByExternalIDParams.cs index f6d31581..58ea8d58 100644 --- a/src/Orb/Models/Customers/Credits/CreditListByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Credits/CreditListByExternalIDParams.cs @@ -1,36 +1,33 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.Credits; /// /// Returns a paginated list of unexpired, non-zero credit blocks for a customer. /// -/// If `include_all_blocks` is set to `true`, all credit blocks (including expired -/// and depleted blocks) will be included in the response. +/// If `include_all_blocks` is set to `true`, all credit blocks (including +/// expired and depleted blocks) will be included in the response. /// -/// Note that `currency` defaults to credits if not specified. To use a real world -/// currency, set `currency` to an ISO 4217 string. +/// Note that `currency` defaults to credits if not specified. To use a real +/// world currency, set `currency` to an ISO 4217 string. /// -public sealed record class CreditListByExternalIDParams : Orb::ParamsBase +public sealed record class CreditListByExternalIDParams : ParamsBase { - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } /// /// The ledger currency or custom pricing unit to use. /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// @@ -39,39 +36,25 @@ public string? Currency /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// - /// If set to True, all expired and depleted blocks, as well as active block will - /// be returned. + /// If set to True, all expired and depleted blocks, as well as active block + /// will be returned. /// public bool? IncludeAllBlocks { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "include_all_blocks"); } + init { - if ( - !this.QueryProperties.TryGetValue( - "include_all_blocks", - out Json::JsonElement element - ) - ) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["include_all_blocks"] = Json::JsonSerializer.SerializeToElement( - value - ); + JsonModel.Set(this._rawQueryData, "include_all_blocks", value); } } @@ -80,36 +63,76 @@ public bool? IncludeAllBlocks /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public CreditListByExternalIDParams() { } + + public CreditListByExternalIDParams(CreditListByExternalIDParams creditListByExternalIDParams) + : base(creditListByExternalIDParams) { } + + public CreditListByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditListByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CreditListByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/credits", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/Credits/CreditListByExternalIDResponse.cs b/src/Orb/Models/Customers/Credits/CreditListByExternalIDResponse.cs new file mode 100644 index 00000000..28bb5c2a --- /dev/null +++ b/src/Orb/Models/Customers/Credits/CreditListByExternalIDResponse.cs @@ -0,0 +1,372 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.Credits; + +[JsonConverter( + typeof(JsonModelConverter< + CreditListByExternalIDResponse, + CreditListByExternalIDResponseFromRaw + >) +)] +public sealed record class CreditListByExternalIDResponse : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required double Balance + { + get { return JsonModel.GetNotNullStruct(this.RawData, "balance"); } + init { JsonModel.Set(this._rawData, "balance", value); } + } + + public required System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); + } + init { JsonModel.Set(this._rawData, "effective_date", value); } + } + + public required System::DateTimeOffset? ExpiryDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); + } + init { JsonModel.Set(this._rawData, "expiry_date", value); } + } + + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + public required double? MaximumInitialBalance + { + get { return JsonModel.GetNullableStruct(this.RawData, "maximum_initial_balance"); } + init { JsonModel.Set(this._rawData, "maximum_initial_balance", value); } + } + + public required string? PerUnitCostBasis + { + get { return JsonModel.GetNullableClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + public required ApiEnum Status + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); + } + init { JsonModel.Set(this._rawData, "status", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Balance; + _ = this.EffectiveDate; + _ = this.ExpiryDate; + foreach (var item in this.Filters) + { + item.Validate(); + } + _ = this.MaximumInitialBalance; + _ = this.PerUnitCostBasis; + this.Status.Validate(); + } + + public CreditListByExternalIDResponse() { } + + public CreditListByExternalIDResponse( + CreditListByExternalIDResponse creditListByExternalIDResponse + ) + : base(creditListByExternalIDResponse) { } + + public CreditListByExternalIDResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditListByExternalIDResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CreditListByExternalIDResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreditListByExternalIDResponseFromRaw : IFromRawJson +{ + /// + public CreditListByExternalIDResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CreditListByExternalIDResponse.FromRawUnchecked(rawData); +} + +/// +/// A PriceFilter that only allows item_id field for block filters. +/// +[JsonConverter( + typeof(JsonModelConverter< + CreditListByExternalIDResponseFilter, + CreditListByExternalIDResponseFilterFromRaw + >) +)] +public sealed record class CreditListByExternalIDResponseFilter : JsonModel +{ + /// + /// The property of the price the block applies to. Only item_id is supported. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public CreditListByExternalIDResponseFilter() { } + + public CreditListByExternalIDResponseFilter( + CreditListByExternalIDResponseFilter creditListByExternalIDResponseFilter + ) + : base(creditListByExternalIDResponseFilter) { } + + public CreditListByExternalIDResponseFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditListByExternalIDResponseFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CreditListByExternalIDResponseFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreditListByExternalIDResponseFilterFromRaw + : IFromRawJson +{ + /// + public CreditListByExternalIDResponseFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CreditListByExternalIDResponseFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price the block applies to. Only item_id is supported. +/// +[JsonConverter(typeof(CreditListByExternalIDResponseFilterFieldConverter))] +public enum CreditListByExternalIDResponseFilterField +{ + ItemID, +} + +sealed class CreditListByExternalIDResponseFilterFieldConverter + : JsonConverter +{ + public override CreditListByExternalIDResponseFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "item_id" => CreditListByExternalIDResponseFilterField.ItemID, + _ => (CreditListByExternalIDResponseFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CreditListByExternalIDResponseFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CreditListByExternalIDResponseFilterField.ItemID => "item_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(CreditListByExternalIDResponseFilterOperatorConverter))] +public enum CreditListByExternalIDResponseFilterOperator +{ + Includes, + Excludes, +} + +sealed class CreditListByExternalIDResponseFilterOperatorConverter + : JsonConverter +{ + public override CreditListByExternalIDResponseFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => CreditListByExternalIDResponseFilterOperator.Includes, + "excludes" => CreditListByExternalIDResponseFilterOperator.Excludes, + _ => (CreditListByExternalIDResponseFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CreditListByExternalIDResponseFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CreditListByExternalIDResponseFilterOperator.Includes => "includes", + CreditListByExternalIDResponseFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CreditListByExternalIDResponseStatusConverter))] +public enum CreditListByExternalIDResponseStatus +{ + Active, + PendingPayment, +} + +sealed class CreditListByExternalIDResponseStatusConverter + : JsonConverter +{ + public override CreditListByExternalIDResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => CreditListByExternalIDResponseStatus.Active, + "pending_payment" => CreditListByExternalIDResponseStatus.PendingPayment, + _ => (CreditListByExternalIDResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CreditListByExternalIDResponseStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CreditListByExternalIDResponseStatus.Active => "active", + CreditListByExternalIDResponseStatus.PendingPayment => "pending_payment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Credits/CreditListPage.cs b/src/Orb/Models/Customers/Credits/CreditListPage.cs new file mode 100644 index 00000000..5244392a --- /dev/null +++ b/src/Orb/Models/Customers/Credits/CreditListPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers; + +namespace Orb.Models.Customers.Credits; + +public sealed class CreditListPage( + ICreditService service, + CreditListParams parameters, + CreditListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/Credits/CreditListPageResponse.cs b/src/Orb/Models/Customers/Credits/CreditListPageResponse.cs index 95f724fc..bbce57ac 100644 --- a/src/Orb/Models/Customers/Credits/CreditListPageResponse.cs +++ b/src/Orb/Models/Customers/Credits/CreditListPageResponse.cs @@ -1,52 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CreditListPageResponseProperties = Orb.Models.Customers.Credits.CreditListPageResponseProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CreditListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +40,35 @@ public override void Validate() public CreditListPageResponse() { } + public CreditListPageResponse(CreditListPageResponse creditListPageResponse) + : base(creditListPageResponse) { } + + public CreditListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CreditListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CreditListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CreditListPageResponseFromRaw : IFromRawJson +{ + /// + public CreditListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CreditListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/CreditListPageResponseProperties/Data.cs b/src/Orb/Models/Customers/Credits/CreditListPageResponseProperties/Data.cs deleted file mode 100644 index 8095e71c..00000000 --- a/src/Orb/Models/Customers/Credits/CreditListPageResponseProperties/Data.cs +++ /dev/null @@ -1,156 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Customers.Credits.CreditListPageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.CreditListPageResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double Balance - { - get - { - if (!this.Properties.TryGetValue("balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["balance"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime? EffectiveDate - { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "effective_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime? ExpiryDate - { - get - { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? MaximumInitialBalance - { - get - { - if ( - !this.Properties.TryGetValue( - "maximum_initial_balance", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "maximum_initial_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["maximum_initial_balance"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required string? PerUnitCostBasis - { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required DataProperties::Status Status - { - get - { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); - } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Balance; - _ = this.EffectiveDate; - _ = this.ExpiryDate; - _ = this.MaximumInitialBalance; - _ = this.PerUnitCostBasis; - this.Status.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/CreditListPageResponseProperties/DataProperties/Status.cs b/src/Orb/Models/Customers/Credits/CreditListPageResponseProperties/DataProperties/Status.cs deleted file mode 100644 index 68febc3f..00000000 --- a/src/Orb/Models/Customers/Credits/CreditListPageResponseProperties/DataProperties/Status.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.CreditListPageResponseProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status PendingPayment = new("pending_payment"); - - readonly string _value = value; - - public enum Value - { - Active, - PendingPayment, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "pending_payment" => Value.PendingPayment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/CreditListParams.cs b/src/Orb/Models/Customers/Credits/CreditListParams.cs index d05eb537..91386c8f 100644 --- a/src/Orb/Models/Customers/Credits/CreditListParams.cs +++ b/src/Orb/Models/Customers/Credits/CreditListParams.cs @@ -1,36 +1,33 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.Credits; /// /// Returns a paginated list of unexpired, non-zero credit blocks for a customer. /// -/// If `include_all_blocks` is set to `true`, all credit blocks (including expired -/// and depleted blocks) will be included in the response. +/// If `include_all_blocks` is set to `true`, all credit blocks (including +/// expired and depleted blocks) will be included in the response. /// -/// Note that `currency` defaults to credits if not specified. To use a real world -/// currency, set `currency` to an ISO 4217 string. +/// Note that `currency` defaults to credits if not specified. To use a real +/// world currency, set `currency` to an ISO 4217 string. /// -public sealed record class CreditListParams : Orb::ParamsBase +public sealed record class CreditListParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } /// /// The ledger currency or custom pricing unit to use. /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// @@ -39,39 +36,25 @@ public string? Currency /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// - /// If set to True, all expired and depleted blocks, as well as active block will - /// be returned. + /// If set to True, all expired and depleted blocks, as well as active block + /// will be returned. /// public bool? IncludeAllBlocks { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "include_all_blocks"); } + init { - if ( - !this.QueryProperties.TryGetValue( - "include_all_blocks", - out Json::JsonElement element - ) - ) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["include_all_blocks"] = Json::JsonSerializer.SerializeToElement( - value - ); + JsonModel.Set(this._rawQueryData, "include_all_blocks", value); } } @@ -80,33 +63,73 @@ public bool? IncludeAllBlocks /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public CreditListParams() { } + + public CreditListParams(CreditListParams creditListParams) + : base(creditListParams) { } + + public CreditListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CreditListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/credits", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/Credits/CreditListResponse.cs b/src/Orb/Models/Customers/Credits/CreditListResponse.cs new file mode 100644 index 00000000..6752488e --- /dev/null +++ b/src/Orb/Models/Customers/Credits/CreditListResponse.cs @@ -0,0 +1,357 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.Credits; + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CreditListResponse : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required double Balance + { + get { return JsonModel.GetNotNullStruct(this.RawData, "balance"); } + init { JsonModel.Set(this._rawData, "balance", value); } + } + + public required System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); + } + init { JsonModel.Set(this._rawData, "effective_date", value); } + } + + public required System::DateTimeOffset? ExpiryDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); + } + init { JsonModel.Set(this._rawData, "expiry_date", value); } + } + + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + public required double? MaximumInitialBalance + { + get { return JsonModel.GetNullableStruct(this.RawData, "maximum_initial_balance"); } + init { JsonModel.Set(this._rawData, "maximum_initial_balance", value); } + } + + public required string? PerUnitCostBasis + { + get { return JsonModel.GetNullableClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + public required ApiEnum Status + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "status"); + } + init { JsonModel.Set(this._rawData, "status", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Balance; + _ = this.EffectiveDate; + _ = this.ExpiryDate; + foreach (var item in this.Filters) + { + item.Validate(); + } + _ = this.MaximumInitialBalance; + _ = this.PerUnitCostBasis; + this.Status.Validate(); + } + + public CreditListResponse() { } + + public CreditListResponse(CreditListResponse creditListResponse) + : base(creditListResponse) { } + + public CreditListResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditListResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CreditListResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreditListResponseFromRaw : IFromRawJson +{ + /// + public CreditListResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + CreditListResponse.FromRawUnchecked(rawData); +} + +/// +/// A PriceFilter that only allows item_id field for block filters. +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Customers.Credits.Filter, + global::Orb.Models.Customers.Credits.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// The property of the price the block applies to. Only item_id is supported. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public Filter() { } + + public Filter(global::Orb.Models.Customers.Credits.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Customers.Credits.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Customers.Credits.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Customers.Credits.Filter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price the block applies to. Only item_id is supported. +/// +[JsonConverter(typeof(global::Orb.Models.Customers.Credits.FieldConverter))] +public enum Field +{ + ItemID, +} + +sealed class FieldConverter : JsonConverter +{ + public override global::Orb.Models.Customers.Credits.Field Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "item_id" => global::Orb.Models.Customers.Credits.Field.ItemID, + _ => (global::Orb.Models.Customers.Credits.Field)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.Credits.Field value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.Credits.Field.ItemID => "item_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(global::Orb.Models.Customers.Credits.OperatorConverter))] +public enum Operator +{ + Includes, + Excludes, +} + +sealed class OperatorConverter : JsonConverter +{ + public override global::Orb.Models.Customers.Credits.Operator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => global::Orb.Models.Customers.Credits.Operator.Includes, + "excludes" => global::Orb.Models.Customers.Credits.Operator.Excludes, + _ => (global::Orb.Models.Customers.Credits.Operator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.Credits.Operator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.Credits.Operator.Includes => "includes", + global::Orb.Models.Customers.Credits.Operator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Customers.Credits.StatusConverter))] +public enum Status +{ + Active, + PendingPayment, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.Customers.Credits.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => global::Orb.Models.Customers.Credits.Status.Active, + "pending_payment" => global::Orb.Models.Customers.Credits.Status.PendingPayment, + _ => (global::Orb.Models.Customers.Credits.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.Credits.Status value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.Credits.Status.Active => "active", + global::Orb.Models.Customers.Credits.Status.PendingPayment => "pending_payment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/AffectedBlock.cs b/src/Orb/Models/Customers/Credits/Ledger/AffectedBlock.cs index 516a36ca..719fd009 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/AffectedBlock.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/AffectedBlock.cs @@ -1,82 +1,274 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AffectedBlock : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AffectedBlock : JsonModel { public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required System::DateTimeOffset? ExpiryDate { get { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "expiry_date", value); } } - public required System::DateTime? ExpiryDate + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullClass>(this.RawData, "filters"); } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } public required string? PerUnitCostBasis { - get + get { return JsonModel.GetNullableClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.ExpiryDate; + foreach (var item in this.Filters) { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); + item.Validate(); + } + _ = this.PerUnitCostBasis; + } + + public AffectedBlock() { } + + public AffectedBlock(AffectedBlock affectedBlock) + : base(affectedBlock) { } + + public AffectedBlock(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } - return Json::JsonSerializer.Deserialize(element); +#pragma warning disable CS8618 + [SetsRequiredMembers] + AffectedBlock(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AffectedBlock FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AffectedBlockFromRaw : IFromRawJson +{ + /// + public AffectedBlock FromRawUnchecked(IReadOnlyDictionary rawData) => + AffectedBlock.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AffectedBlockFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); } - set + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); } + init { JsonModel.Set(this._rawData, "operator", value); } } + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// public override void Validate() { - _ = this.ID; - _ = this.ExpiryDate; - _ = this.PerUnitCostBasis; + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; } - public AffectedBlock() { } + public AffectedBlockFilter() { } + + public AffectedBlockFilter(AffectedBlockFilter affectedBlockFilter) + : base(affectedBlockFilter) { } + + public AffectedBlockFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AffectedBlock(Generic::Dictionary properties) + [SetsRequiredMembers] + AffectedBlockFilter(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static AffectedBlock FromRawUnchecked( - Generic::Dictionary properties + /// + public static AffectedBlockFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AffectedBlockFilterFromRaw : IFromRawJson +{ + /// + public AffectedBlockFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + AffectedBlockFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(AffectedBlockFilterFieldConverter))] +public enum AffectedBlockFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class AffectedBlockFilterFieldConverter : JsonConverter +{ + public override AffectedBlockFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => AffectedBlockFilterField.PriceID, + "item_id" => AffectedBlockFilterField.ItemID, + "price_type" => AffectedBlockFilterField.PriceType, + "currency" => AffectedBlockFilterField.Currency, + "pricing_unit_id" => AffectedBlockFilterField.PricingUnitID, + _ => (AffectedBlockFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AffectedBlockFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AffectedBlockFilterField.PriceID => "price_id", + AffectedBlockFilterField.ItemID => "item_id", + AffectedBlockFilterField.PriceType => "price_type", + AffectedBlockFilterField.Currency => "currency", + AffectedBlockFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(AffectedBlockFilterOperatorConverter))] +public enum AffectedBlockFilterOperator +{ + Includes, + Excludes, +} + +sealed class AffectedBlockFilterOperatorConverter : JsonConverter +{ + public override AffectedBlockFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => AffectedBlockFilterOperator.Includes, + "excludes" => AffectedBlockFilterOperator.Excludes, + _ => (AffectedBlockFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AffectedBlockFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + AffectedBlockFilterOperator.Includes => "includes", + AffectedBlockFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntry.cs index 58bcd11e..07f5d712 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntry.cs @@ -1,197 +1,96 @@ -using AmendmentLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.AmendmentLedgerEntryProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AmendmentLedgerEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AmendmentLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required AmendmentLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_status" + ); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required AmendmentLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_type" + ); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -200,40 +99,22 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } + /// public override void Validate() { _ = this.ID; @@ -247,27 +128,127 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.StartingBalance; } public AmendmentLedgerEntry() { } + public AmendmentLedgerEntry(AmendmentLedgerEntry amendmentLedgerEntry) + : base(amendmentLedgerEntry) { } + + public AmendmentLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AmendmentLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + AmendmentLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static AmendmentLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AmendmentLedgerEntryFromRaw : IFromRawJson +{ + /// + public AmendmentLedgerEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AmendmentLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(AmendmentLedgerEntryEntryStatusConverter))] +public enum AmendmentLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class AmendmentLedgerEntryEntryStatusConverter + : JsonConverter +{ + public override AmendmentLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => AmendmentLedgerEntryEntryStatus.Committed, + "pending" => AmendmentLedgerEntryEntryStatus.Pending, + _ => (AmendmentLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmendmentLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AmendmentLedgerEntryEntryStatus.Committed => "committed", + AmendmentLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(AmendmentLedgerEntryEntryTypeConverter))] +public enum AmendmentLedgerEntryEntryType +{ + Amendment, +} + +sealed class AmendmentLedgerEntryEntryTypeConverter : JsonConverter +{ + public override AmendmentLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "amendment" => AmendmentLedgerEntryEntryType.Amendment, + _ => (AmendmentLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AmendmentLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + AmendmentLedgerEntryEntryType.Amendment => "amendment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index 5a763918..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.AmendmentLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntryProperties/EntryType.cs deleted file mode 100644 index aafe392a..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/AmendmentLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.AmendmentLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Amendment = new("amendment"); - - readonly string _value = value; - - public enum Value - { - Amendment, - } - - public Value Known() => - _value switch - { - "amendment" => Value.Amendment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntry.cs index c039b745..cee43ddf 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntry.cs @@ -1,197 +1,96 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CreditBlockExpiryLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.CreditBlockExpiryLedgerEntryProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditBlockExpiryLedgerEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CreditBlockExpiryLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required CreditBlockExpiryLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "entry_status"); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required CreditBlockExpiryLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "entry_type"); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -200,40 +99,22 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } + /// public override void Validate() { _ = this.ID; @@ -247,27 +128,128 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.StartingBalance; } public CreditBlockExpiryLedgerEntry() { } + public CreditBlockExpiryLedgerEntry(CreditBlockExpiryLedgerEntry creditBlockExpiryLedgerEntry) + : base(creditBlockExpiryLedgerEntry) { } + + public CreditBlockExpiryLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditBlockExpiryLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + CreditBlockExpiryLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CreditBlockExpiryLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreditBlockExpiryLedgerEntryFromRaw : IFromRawJson +{ + /// + public CreditBlockExpiryLedgerEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CreditBlockExpiryLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CreditBlockExpiryLedgerEntryEntryStatusConverter))] +public enum CreditBlockExpiryLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class CreditBlockExpiryLedgerEntryEntryStatusConverter + : JsonConverter +{ + public override CreditBlockExpiryLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => CreditBlockExpiryLedgerEntryEntryStatus.Committed, + "pending" => CreditBlockExpiryLedgerEntryEntryStatus.Pending, + _ => (CreditBlockExpiryLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CreditBlockExpiryLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CreditBlockExpiryLedgerEntryEntryStatus.Committed => "committed", + CreditBlockExpiryLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CreditBlockExpiryLedgerEntryEntryTypeConverter))] +public enum CreditBlockExpiryLedgerEntryEntryType +{ + CreditBlockExpiry, +} + +sealed class CreditBlockExpiryLedgerEntryEntryTypeConverter + : JsonConverter +{ + public override CreditBlockExpiryLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "credit_block_expiry" => CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry, + _ => (CreditBlockExpiryLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CreditBlockExpiryLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + CreditBlockExpiryLedgerEntryEntryType.CreditBlockExpiry => "credit_block_expiry", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index 2e48df70..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.CreditBlockExpiryLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryProperties/EntryType.cs deleted file mode 100644 index 0f8bf6f4..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/CreditBlockExpiryLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.CreditBlockExpiryLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType CreditBlockExpiry = new("credit_block_expiry"); - - readonly string _value = value; - - public enum Value - { - CreditBlockExpiry, - } - - public Value Known() => - _value switch - { - "credit_block_expiry" => Value.CreditBlockExpiry, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntry.cs index c5064574..45bf8a34 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntry.cs @@ -1,197 +1,96 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DecrementLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.DecrementLedgerEntryProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class DecrementLedgerEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class DecrementLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required DecrementLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_status" + ); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required DecrementLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_type" + ); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -200,76 +99,40 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } public string? EventID { - get - { - if (!this.Properties.TryGetValue("event_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["event_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "event_id"); } + init { JsonModel.Set(this._rawData, "event_id", value); } } public string? InvoiceID { - get - { - if (!this.Properties.TryGetValue("invoice_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_id"); } + init { JsonModel.Set(this._rawData, "invoice_id", value); } } public string? PriceID { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } } + /// public override void Validate() { _ = this.ID; @@ -283,10 +146,7 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.StartingBalance; _ = this.EventID; _ = this.InvoiceID; @@ -295,18 +155,121 @@ public override void Validate() public DecrementLedgerEntry() { } + public DecrementLedgerEntry(DecrementLedgerEntry decrementLedgerEntry) + : base(decrementLedgerEntry) { } + + public DecrementLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - DecrementLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + DecrementLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static DecrementLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DecrementLedgerEntryFromRaw : IFromRawJson +{ + /// + public DecrementLedgerEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => DecrementLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DecrementLedgerEntryEntryStatusConverter))] +public enum DecrementLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class DecrementLedgerEntryEntryStatusConverter + : JsonConverter +{ + public override DecrementLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => DecrementLedgerEntryEntryStatus.Committed, + "pending" => DecrementLedgerEntryEntryStatus.Pending, + _ => (DecrementLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + DecrementLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + DecrementLedgerEntryEntryStatus.Committed => "committed", + DecrementLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(DecrementLedgerEntryEntryTypeConverter))] +public enum DecrementLedgerEntryEntryType +{ + Decrement, +} + +sealed class DecrementLedgerEntryEntryTypeConverter : JsonConverter +{ + public override DecrementLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "decrement" => DecrementLedgerEntryEntryType.Decrement, + _ => (DecrementLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + DecrementLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + DecrementLedgerEntryEntryType.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index 95fe3c5d..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.DecrementLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntryProperties/EntryType.cs deleted file mode 100644 index a19ec349..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/DecrementLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.DecrementLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Decrement, - } - - public Value Known() => - _value switch - { - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntry.cs index 2dab1c53..fde14820 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntry.cs @@ -1,197 +1,97 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using ExpirationChangeLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.ExpirationChangeLedgerEntryProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ExpirationChangeLedgerEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ExpirationChangeLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required ExpirationChangeLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "entry_status"); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required ExpirationChangeLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_type" + ); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -200,62 +100,34 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } - public required System::DateTime? NewBlockExpiryDate + public required System::DateTimeOffset? NewBlockExpiryDate { get { - if ( - !this.Properties.TryGetValue("new_block_expiry_date", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "new_block_expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["new_block_expiry_date"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawData, + "new_block_expiry_date" ); } + init { JsonModel.Set(this._rawData, "new_block_expiry_date", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } + /// public override void Validate() { _ = this.ID; @@ -269,28 +141,129 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.NewBlockExpiryDate; _ = this.StartingBalance; } public ExpirationChangeLedgerEntry() { } + public ExpirationChangeLedgerEntry(ExpirationChangeLedgerEntry expirationChangeLedgerEntry) + : base(expirationChangeLedgerEntry) { } + + public ExpirationChangeLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ExpirationChangeLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + ExpirationChangeLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static ExpirationChangeLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ExpirationChangeLedgerEntryFromRaw : IFromRawJson +{ + /// + public ExpirationChangeLedgerEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExpirationChangeLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ExpirationChangeLedgerEntryEntryStatusConverter))] +public enum ExpirationChangeLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class ExpirationChangeLedgerEntryEntryStatusConverter + : JsonConverter +{ + public override ExpirationChangeLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => ExpirationChangeLedgerEntryEntryStatus.Committed, + "pending" => ExpirationChangeLedgerEntryEntryStatus.Pending, + _ => (ExpirationChangeLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExpirationChangeLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ExpirationChangeLedgerEntryEntryStatus.Committed => "committed", + ExpirationChangeLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ExpirationChangeLedgerEntryEntryTypeConverter))] +public enum ExpirationChangeLedgerEntryEntryType +{ + ExpirationChange, +} + +sealed class ExpirationChangeLedgerEntryEntryTypeConverter + : JsonConverter +{ + public override ExpirationChangeLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "expiration_change" => ExpirationChangeLedgerEntryEntryType.ExpirationChange, + _ => (ExpirationChangeLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExpirationChangeLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + ExpirationChangeLedgerEntryEntryType.ExpirationChange => "expiration_change", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index 524ae48b..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.ExpirationChangeLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryProperties/EntryType.cs deleted file mode 100644 index 5cc6ea30..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/ExpirationChangeLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.ExpirationChangeLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType ExpirationChange = new("expiration_change"); - - readonly string _value = value; - - public enum Value - { - ExpirationChange, - } - - public Value Known() => - _value switch - { - "expiration_change" => Value.ExpirationChange, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntry.cs index 49b20a20..f6589821 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntry.cs @@ -1,197 +1,96 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using IncrementLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.IncrementLedgerEntryProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class IncrementLedgerEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class IncrementLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required IncrementLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_status" + ); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required IncrementLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_type" + ); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -200,58 +99,31 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } /// /// If the increment resulted in invoice creation, the list of created invoices /// - public Generic::List? CreatedInvoices + public IReadOnlyList? CreatedInvoices { - get - { - if (!this.Properties.TryGetValue("created_invoices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["created_invoices"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass>(this.RawData, "created_invoices"); } + init { JsonModel.Set(this._rawData, "created_invoices", value); } } + /// public override void Validate() { _ = this.ID; @@ -265,10 +137,7 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.StartingBalance; foreach (var item in this.CreatedInvoices ?? []) { @@ -278,18 +147,121 @@ public override void Validate() public IncrementLedgerEntry() { } + public IncrementLedgerEntry(IncrementLedgerEntry incrementLedgerEntry) + : base(incrementLedgerEntry) { } + + public IncrementLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - IncrementLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + IncrementLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static IncrementLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class IncrementLedgerEntryFromRaw : IFromRawJson +{ + /// + public IncrementLedgerEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => IncrementLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(IncrementLedgerEntryEntryStatusConverter))] +public enum IncrementLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class IncrementLedgerEntryEntryStatusConverter + : JsonConverter +{ + public override IncrementLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => IncrementLedgerEntryEntryStatus.Committed, + "pending" => IncrementLedgerEntryEntryStatus.Pending, + _ => (IncrementLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + IncrementLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + IncrementLedgerEntryEntryStatus.Committed => "committed", + IncrementLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(IncrementLedgerEntryEntryTypeConverter))] +public enum IncrementLedgerEntryEntryType +{ + Increment, +} + +sealed class IncrementLedgerEntryEntryTypeConverter : JsonConverter +{ + public override IncrementLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => IncrementLedgerEntryEntryType.Increment, + _ => (IncrementLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + IncrementLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + IncrementLedgerEntryEntryType.Increment => "increment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index baa37a1d..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.IncrementLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntryProperties/EntryType.cs deleted file mode 100644 index e1e83663..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/IncrementLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.IncrementLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Increment = new("increment"); - - readonly string _value = value; - - public enum Value - { - Increment, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParams.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParams.cs index a99dfe9a..656231e8 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using LedgerCreateEntryByExternalIDParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Customers.Credits.Ledger; @@ -13,131 +16,2467 @@ namespace Orb.Models.Customers.Credits.Ledger; /// balance. This can be used to increment balance, deduct credits, and change the /// expiry date of existing credits. /// -/// ## Effects of adding a ledger entry 1. After calling this endpoint, [Fetch Credit -/// Balance](fetch-customer-credits) will return a credit block that represents +/// ## Effects of adding a ledger entry 1. After calling this endpoint, [Fetch +/// Credit Balance](fetch-customer-credits) will return a credit block that represents /// the changes (i.e. balance changes or transfers). 2. A ledger entry will be added /// to the credits ledger for this customer, and therefore returned in the [View /// Credits Ledger](fetch-customer-credits-ledger) response as well as serialized /// in the response to this request. In the case of deductions without a specified /// block, multiple ledger entries may be created if the deduction spans credit /// blocks. 3. If `invoice_settings` is specified, an invoice will be created that -/// reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). +/// reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). /// -/// ## Adding credits Adding credits is done by creating an entry of type `increment`. -/// This requires the caller to specify a number of credits as well as an optional -/// expiry date in `YYYY-MM-DD` format. Orb also recommends specifying a description -/// to assist with auditing. When adding credits, the caller can also specify a -/// cost basis per-credit, to indicate how much in USD a customer paid for a single -/// credit in a block. This can later be used for revenue recognition. +/// ## Adding credits Adding credits is done by creating an entry of type +/// `increment`. This requires the caller to specify a number of credits as well +/// as an optional expiry date in `YYYY-MM-DD` format. Orb also recommends specifying +/// a description to assist with auditing. When adding credits, the caller can +/// also specify a cost basis per-credit, to indicate how much in USD a customer +/// paid for a single credit in a block. This can later be used for revenue recognition. /// -/// The following snippet illustrates a sample request body to increment credits -/// which will expire in January of 2022. +/// The following snippet illustrates a sample request body to increment credits +/// which will expire in January of 2022. /// -/// ```json { "entry_type": "increment", "amount": 100, "expiry_date": "2022-12-28", -/// "per_unit_cost_basis": "0.20", "description": "Purchased 100 credits" } ``` +/// ```json { "entry_type": "increment", "amount": 100, "expiry_date": +/// "2022-12-28", "per_unit_cost_basis": "0.20", "description": "Purchased 100 +/// credits" } ``` /// -/// Note that by default, Orb will always first increment any _negative_ balance in -/// existing blocks before adding the remaining amount to the desired credit block. +/// Note that by default, Orb will always first increment any _negative_ balance +/// in existing blocks before adding the remaining amount to the desired credit block. /// -/// ### Invoicing for credits By default, Orb manipulates the credit ledger but does -/// not charge for credits. However, if you pass `invoice_settings` in the body of -/// this request, Orb will also generate a one-off invoice for the customer for the -/// credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, +/// ### Invoicing for credits By default, Orb manipulates the credit ledger +/// but does not charge for credits. However, if you pass `invoice_settings` in the +/// body of this request, Orb will also generate a one-off invoice for the customer +/// for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, /// since the total charges on the invoice are calculated by multiplying the cost -/// basis with the number of credit units added. +/// basis with the number of credit units added. /// -/// ## Deducting Credits Orb allows you to deduct credits from a customer by creating -/// an entry of type `decrement`. Orb matches the algorithm for automatic deductions -/// for determining which credit blocks to decrement from. In the case that the deduction -/// leads to multiple ledger entries, the response from this endpoint will be the -/// final deduction. Orb also optionally allows specifying a description to assist -/// with auditing. +/// ## Deducting Credits Orb allows you to deduct credits from a customer by +/// creating an entry of type `decrement`. Orb matches the algorithm for automatic +/// deductions for determining which credit blocks to decrement from. In the case +/// that the deduction leads to multiple ledger entries, the response from this endpoint +/// will be the final deduction. Orb also optionally allows specifying a description +/// to assist with auditing. /// -/// The following snippet illustrates a sample request body to decrement credits. +/// The following snippet illustrates a sample request body to decrement credits. /// -/// ```json { "entry_type": "decrement", "amount": 20, "description": "Removing -/// excess credits" } ``` +/// ```json { "entry_type": "decrement", "amount": 20, "description": +/// "Removing excess credits" } ``` /// -/// ## Changing credits expiry If you'd like to change when existing credits expire, -/// you should create a ledger entry of type `expiration_change`. For this entry, -/// the required parameter `expiry_date` identifies the _originating_ block, and the -/// required parameter `target_expiry_date` identifies when the transferred credits -/// should now expire. A new credit block will be created with expiry date `target_expiry_date`, -/// with the same cost basis data as the original credit block, if present. +/// ## Changing credits expiry If you'd like to change when existing credits +/// expire, you should create a ledger entry of type `expiration_change`. For this +/// entry, the required parameter `expiry_date` identifies the _originating_ block, +/// and the required parameter `target_expiry_date` identifies when the transferred +/// credits should now expire. A new credit block will be created with expiry date +/// `target_expiry_date`, with the same cost basis data as the original credit block, +/// if present. /// -/// Note that the balance of the block with the given `expiry_date` must be at least -/// equal to the desired transfer amount determined by the `amount` parameter. +/// Note that the balance of the block with the given `expiry_date` must be +/// at least equal to the desired transfer amount determined by the `amount` parameter. /// -/// The following snippet illustrates a sample request body to extend the expiration -/// date of credits by one year: +/// The following snippet illustrates a sample request body to extend the expiration +/// date of credits by one year: /// -/// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": +/// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": /// "2022-12-28", "block_id": "UiUhFWeLHPrBY4Ad", "target_expiry_date": "2023-12-28", -/// "description": "Extending credit validity" } ``` +/// "description": "Extending credit validity" } ``` /// -/// ## Voiding credits +/// ## Voiding credits /// -/// If you'd like to void a credit block, create a ledger entry of type `void`. For -/// this entry, `block_id` is required to identify the block, and `amount` indicates +/// If you'd like to void a credit block, create a ledger entry of type `void`. +/// For this entry, `block_id` is required to identify the block, and `amount` indicates /// how many credits to void, up to the block's initial balance. Pass in a `void_reason` -/// of `refund` if the void is due to a refund. +/// of `refund` if the void is due to a refund. /// -/// ## Amendment +/// ## Amendment /// -/// If you'd like to undo a decrement on a credit block, create a ledger entry of -/// type `amendment`. For this entry, `block_id` is required to identify the block +/// If you'd like to undo a decrement on a credit block, create a ledger entry +/// of type `amendment`. For this entry, `block_id` is required to identify the block /// that was originally decremented from, and `amount` indicates how many credits -/// to return to the customer, up to the block's initial balance. +/// to return to the customer, up to the block's initial balance. /// -public sealed record class LedgerCreateEntryByExternalIDParams : Orb::ParamsBase +public sealed record class LedgerCreateEntryByExternalIDParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } - public required LedgerCreateEntryByExternalIDParamsProperties::Body Body + public required LedgerCreateEntryByExternalIDParamsBody Body { get { - if (!this.BodyProperties.TryGetValue("body", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("body", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("body"); + return JsonModel.GetNotNullClass( + this.RawBodyData, + "body" + ); } - set { this.BodyProperties["body"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "body", value); } + } + + public LedgerCreateEntryByExternalIDParams() { } + + public LedgerCreateEntryByExternalIDParams( + LedgerCreateEntryByExternalIDParams ledgerCreateEntryByExternalIDParams + ) + : base(ledgerCreateEntryByExternalIDParams) + { + this._rawBodyData = [.. ledgerCreateEntryByExternalIDParams._rawBodyData]; + } + + public LedgerCreateEntryByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/credits/ledger_entry", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +[JsonConverter(typeof(LedgerCreateEntryByExternalIDParamsBodyConverter))] +public record class LedgerCreateEntryByExternalIDParamsBody +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public double? Amount + { + get + { + return Match( + increment: (x) => x.Amount, + decrement: (x) => x.Amount, + expirationChange: (x) => x.Amount, + void1: (x) => x.Amount, + amendment: (x) => x.Amount + ); + } + } + + public JsonElement EntryType + { + get + { + return Match( + increment: (x) => x.EntryType, + decrement: (x) => x.EntryType, + expirationChange: (x) => x.EntryType, + void1: (x) => x.EntryType, + amendment: (x) => x.EntryType + ); + } + } + + public string? Currency + { + get + { + return Match( + increment: (x) => x.Currency, + decrement: (x) => x.Currency, + expirationChange: (x) => x.Currency, + void1: (x) => x.Currency, + amendment: (x) => x.Currency + ); + } + } + + public string? Description + { + get + { + return Match( + increment: (x) => x.Description, + decrement: (x) => x.Description, + expirationChange: (x) => x.Description, + void1: (x) => x.Description, + amendment: (x) => x.Description + ); + } + } + + public System::DateTimeOffset? ExpiryDate + { + get + { + return Match( + increment: (x) => x.ExpiryDate, + decrement: (_) => null, + expirationChange: (x) => x.ExpiryDate, + void1: (_) => null, + amendment: (_) => null + ); + } + } + + public string? BlockID + { + get + { + return Match( + increment: (_) => null, + decrement: (_) => null, + expirationChange: (x) => x.BlockID, + void1: (x) => x.BlockID, + amendment: (x) => x.BlockID + ); + } + } + + public LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyIncrement value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyDecrement value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyExpirationChange value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyVoid value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyAmendment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBody(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickIncrement(out var value)) { + /// // `value` is of type `LedgerCreateEntryByExternalIDParamsBodyIncrement` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickIncrement( + [NotNullWhen(true)] out LedgerCreateEntryByExternalIDParamsBodyIncrement? value + ) + { + value = this.Value as LedgerCreateEntryByExternalIDParamsBodyIncrement; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDecrement(out var value)) { + /// // `value` is of type `LedgerCreateEntryByExternalIDParamsBodyDecrement` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDecrement( + [NotNullWhen(true)] out LedgerCreateEntryByExternalIDParamsBodyDecrement? value + ) + { + value = this.Value as LedgerCreateEntryByExternalIDParamsBodyDecrement; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickExpirationChange(out var value)) { + /// // `value` is of type `LedgerCreateEntryByExternalIDParamsBodyExpirationChange` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickExpirationChange( + [NotNullWhen(true)] out LedgerCreateEntryByExternalIDParamsBodyExpirationChange? value + ) + { + value = this.Value as LedgerCreateEntryByExternalIDParamsBodyExpirationChange; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoid(out var value)) { + /// // `value` is of type `LedgerCreateEntryByExternalIDParamsBodyVoid` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoid( + [NotNullWhen(true)] out LedgerCreateEntryByExternalIDParamsBodyVoid? value + ) + { + value = this.Value as LedgerCreateEntryByExternalIDParamsBodyVoid; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmendment(out var value)) { + /// // `value` is of type `LedgerCreateEntryByExternalIDParamsBodyAmendment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmendment( + [NotNullWhen(true)] out LedgerCreateEntryByExternalIDParamsBodyAmendment? value + ) + { + value = this.Value as LedgerCreateEntryByExternalIDParamsBodyAmendment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (LedgerCreateEntryByExternalIDParamsBodyIncrement value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyDecrement value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyExpirationChange value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyVoid value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyAmendment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action increment, + System::Action decrement, + System::Action expirationChange, + System::Action void1, + System::Action amendment + ) + { + switch (this.Value) + { + case LedgerCreateEntryByExternalIDParamsBodyIncrement value: + increment(value); + break; + case LedgerCreateEntryByExternalIDParamsBodyDecrement value: + decrement(value); + break; + case LedgerCreateEntryByExternalIDParamsBodyExpirationChange value: + expirationChange(value); + break; + case LedgerCreateEntryByExternalIDParamsBodyVoid value: + void1(value); + break; + case LedgerCreateEntryByExternalIDParamsBodyAmendment value: + amendment(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBody" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (LedgerCreateEntryByExternalIDParamsBodyIncrement value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyDecrement value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyExpirationChange value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyVoid value) => {...}, + /// (LedgerCreateEntryByExternalIDParamsBodyAmendment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func increment, + System::Func decrement, + System::Func expirationChange, + System::Func void1, + System::Func amendment + ) + { + return this.Value switch + { + LedgerCreateEntryByExternalIDParamsBodyIncrement value => increment(value), + LedgerCreateEntryByExternalIDParamsBodyDecrement value => decrement(value), + LedgerCreateEntryByExternalIDParamsBodyExpirationChange value => expirationChange( + value + ), + LedgerCreateEntryByExternalIDParamsBodyVoid value => void1(value), + LedgerCreateEntryByExternalIDParamsBodyAmendment value => amendment(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBody" + ), + }; + } + + public static implicit operator LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyIncrement value + ) => new(value); + + public static implicit operator LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyDecrement value + ) => new(value); + + public static implicit operator LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyExpirationChange value + ) => new(value); + + public static implicit operator LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyVoid value + ) => new(value); + + public static implicit operator LedgerCreateEntryByExternalIDParamsBody( + LedgerCreateEntryByExternalIDParamsBodyAmendment value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBody" + ); + } + this.Switch( + (increment) => increment.Validate(), + (decrement) => decrement.Validate(), + (expirationChange) => expirationChange.Validate(), + (void1) => void1.Validate(), + (amendment) => amendment.Validate() + ); + } + + public virtual bool Equals(LedgerCreateEntryByExternalIDParamsBody? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerCreateEntryByExternalIDParamsBodyConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDParamsBody? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? entryType; + try + { + entryType = element.GetProperty("entry_type").GetString(); + } + catch + { + entryType = null; + } + + switch (entryType) + { + case "increment": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "decrement": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "expiration_change": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amendment": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new LedgerCreateEntryByExternalIDParamsBody(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDParamsBody value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyIncrement, + LedgerCreateEntryByExternalIDParamsBodyIncrementFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyIncrement : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// An ISO 8601 format date that denotes when this credit balance should become + /// available for use. + /// + public System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); + } + init { JsonModel.Set(this._rawData, "effective_date", value); } + } + + /// + /// An ISO 8601 format date that denotes when this credit balance should expire. + /// + public System::DateTimeOffset? ExpiryDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); + } + init { JsonModel.Set(this._rawData, "expiry_date", value); } + } + + /// + /// Optional filter to specify which items this credit block applies to. If not + /// specified, the block will apply to all items for the pricing unit. + /// + public IReadOnlyList? Filters + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Passing `invoice_settings` automatically generates an invoice for the newly + /// added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, + /// as the calculation of the invoice total is done on that basis. + /// + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings? InvoiceSettings + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoice_settings" + ); + } + init { JsonModel.Set(this._rawData, "invoice_settings", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// Can only be specified when entry_type=increment. How much, in the customer's + /// currency, a customer paid for a single credit in this block + /// + public string? PerUnitCostBasis + { + get { return JsonModel.GetNullableClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"increment\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.EffectiveDate; + _ = this.ExpiryDate; + foreach (var item in this.Filters ?? []) + { + item.Validate(); + } + this.InvoiceSettings?.Validate(); + _ = this.Metadata; + _ = this.PerUnitCostBasis; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrement() + { + this.EntryType = JsonSerializer.Deserialize("\"increment\""); + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrement( + LedgerCreateEntryByExternalIDParamsBodyIncrement ledgerCreateEntryByExternalIDParamsBodyIncrement + ) + : base(ledgerCreateEntryByExternalIDParamsBodyIncrement) { } + + public LedgerCreateEntryByExternalIDParamsBodyIncrement( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"increment\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyIncrement(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyIncrement FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public LedgerCreateEntryByExternalIDParamsBodyIncrement(double amount) + : this() + { + this.Amount = amount; + } +} + +class LedgerCreateEntryByExternalIDParamsBodyIncrementFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyIncrement FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyIncrement.FromRawUnchecked(rawData); +} + +/// +/// A PriceFilter that only allows item_id field for block filters. +/// +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyIncrementFilter, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyIncrementFilter : JsonModel +{ + /// + /// The property of the price the block applies to. Only item_id is supported. + /// + public required ApiEnum< + string, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField + > Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum< + string, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator + > Operator { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementFilter() { } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementFilter( + LedgerCreateEntryByExternalIDParamsBodyIncrementFilter ledgerCreateEntryByExternalIDParamsBodyIncrementFilter + ) + : base(ledgerCreateEntryByExternalIDParamsBodyIncrementFilter) { } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyIncrementFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyIncrementFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class LedgerCreateEntryByExternalIDParamsBodyIncrementFilterFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyIncrementFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyIncrementFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price the block applies to. Only item_id is supported. +/// +[JsonConverter(typeof(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterFieldConverter))] +public enum LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField +{ + ItemID, +} + +sealed class LedgerCreateEntryByExternalIDParamsBodyIncrementFilterFieldConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "item_id" => LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID, + _ => (LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterField.ItemID => "item_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperatorConverter))] +public enum LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator +{ + Includes, + Excludes, +} + +sealed class LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperatorConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes, + "excludes" => LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Excludes, + _ => (LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Includes => + "includes", + LedgerCreateEntryByExternalIDParamsBodyIncrementFilterOperator.Excludes => + "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Passing `invoice_settings` automatically generates an invoice for the newly added +/// credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, +/// as the calculation of the invoice total is done on that basis. +/// +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings, + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + : JsonModel +{ + /// + /// Whether the credits purchase invoice should auto collect with the customer's + /// saved payment method. + /// + public required bool AutoCollection + { + get { return JsonModel.GetNotNullStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } + } + + /// + /// An optional custom due date for the invoice. If not set, the due date will + /// be calculated based on the `net_terms` value. + /// + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate? CustomDueDate + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "custom_due_date" + ); + } + init { JsonModel.Set(this._rawData, "custom_due_date", value); } + } + + /// + /// An ISO 8601 format date that denotes when this invoice should be dated in + /// the customer's timezone. If not provided, the invoice date will default to + /// the credit block's effective date. + /// + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate? InvoiceDate + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoice_date" + ); + } + init { JsonModel.Set(this._rawData, "invoice_date", value); } + } + + /// + /// The ID of the Item to be used for the invoice line item. If not provided, + /// a default 'Credits' item will be used. + /// + public string? ItemID + { + get { return JsonModel.GetNullableClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// An optional memo to display on the invoice. + /// + public string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + /// + /// The net terms determines the due date of the invoice. Due date is calculated + /// based on the invoice or issuance date, depending on the account's configured + /// due date calculation method. A value of '0' here represents that the invoice + /// is due on issue, whereas a value of '30' represents that the customer has + /// 30 days to pay the invoice. Do not set this field if you want to set a custom + /// due date. + /// + public long? NetTerms + { + get { return JsonModel.GetNullableStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } + } + + /// + /// If true, the new credit block will require that the corresponding invoice + /// is paid before it can be drawn down from. + /// + public bool? RequireSuccessfulPayment + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "require_successful_payment"); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "require_successful_payment", value); + } + } + + /// + public override void Validate() + { + _ = this.AutoCollection; + this.CustomDueDate?.Validate(); + this.InvoiceDate?.Validate(); + _ = this.ItemID; + _ = this.Memo; + _ = this.NetTerms; + _ = this.RequireSuccessfulPayment; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings() { } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings( + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings ledgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings + ) + : base(ledgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings) { } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings(bool autoCollection) + : this() + { + this.AutoCollection = autoCollection; + } +} + +class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettings.FromRawUnchecked(rawData); +} + +/// +/// An optional custom due date for the invoice. If not set, the due date will be +/// calculated based on the `net_terms` value. +/// +[JsonConverter( + typeof(LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDateConverter) +)] +public record class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate( + string value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate( + System::DateTimeOffset value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @date, + System::Func @dateTime + ) + { + return this.Value switch + { + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate" + ), + }; + } + + public static implicit operator LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate( + string value + ) => new(value); + + public static implicit operator LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate( + System::DateTimeOffset value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate" + ); + } + } + + public virtual bool Equals( + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDateConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsCustomDueDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +/// +/// An ISO 8601 format date that denotes when this invoice should be dated in the +/// customer's timezone. If not provided, the invoice date will default to the credit +/// block's effective date. +/// +[JsonConverter( + typeof(LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDateConverter) +)] +public record class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate( + string value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate( + System::DateTimeOffset value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @date, + System::Func @dateTime + ) + { + return this.Value switch + { + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate" + ), + }; + } + + public static implicit operator LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate( + string value + ) => new(value); + + public static implicit operator LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate( + System::DateTimeOffset value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate" + ); + } + } + + public virtual bool Equals( + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDateConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDParamsBodyIncrementInvoiceSettingsInvoiceDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyDecrement, + LedgerCreateEntryByExternalIDParamsBodyDecrementFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyDecrement : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"decrement\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.Metadata; + } + + public LedgerCreateEntryByExternalIDParamsBodyDecrement() + { + this.EntryType = JsonSerializer.Deserialize("\"decrement\""); + } + + public LedgerCreateEntryByExternalIDParamsBodyDecrement( + LedgerCreateEntryByExternalIDParamsBodyDecrement ledgerCreateEntryByExternalIDParamsBodyDecrement + ) + : base(ledgerCreateEntryByExternalIDParamsBodyDecrement) { } + + public LedgerCreateEntryByExternalIDParamsBodyDecrement( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"decrement\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyDecrement(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyDecrement FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public LedgerCreateEntryByExternalIDParamsBodyDecrement(double amount) + : this() + { + this.Amount = amount; + } +} + +class LedgerCreateEntryByExternalIDParamsBodyDecrementFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyDecrement FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyDecrement.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyExpirationChange, + LedgerCreateEntryByExternalIDParamsBodyExpirationChangeFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyExpirationChange : JsonModel +{ + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// A future date (specified in YYYY-MM-DD format) used for expiration change, + /// denoting when credits transferred (as part of a partial block expiration) + /// should expire. + /// + public required string TargetExpiryDate + { + get { return JsonModel.GetNotNullClass(this.RawData, "target_expiry_date"); } + init { JsonModel.Set(this._rawData, "target_expiry_date", value); } + } + + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public double? Amount + { + get { return JsonModel.GetNullableStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the block affected by an expiration_change, used to differentiate + /// between multiple blocks with the same `expiry_date`. + /// + public string? BlockID + { + get { return JsonModel.GetNullableClass(this.RawData, "block_id"); } + init { JsonModel.Set(this._rawData, "block_id", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// An ISO 8601 format date that identifies the origination credit block to expire + /// + public System::DateTimeOffset? ExpiryDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); + } + init { JsonModel.Set(this._rawData, "expiry_date", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"expiration_change\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.TargetExpiryDate; + _ = this.Amount; + _ = this.BlockID; + _ = this.Currency; + _ = this.Description; + _ = this.ExpiryDate; + _ = this.Metadata; + } + + public LedgerCreateEntryByExternalIDParamsBodyExpirationChange() + { + this.EntryType = JsonSerializer.Deserialize("\"expiration_change\""); + } + + public LedgerCreateEntryByExternalIDParamsBodyExpirationChange( + LedgerCreateEntryByExternalIDParamsBodyExpirationChange ledgerCreateEntryByExternalIDParamsBodyExpirationChange + ) + : base(ledgerCreateEntryByExternalIDParamsBodyExpirationChange) { } + + public LedgerCreateEntryByExternalIDParamsBodyExpirationChange( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"expiration_change\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyExpirationChange( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyExpirationChange FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public LedgerCreateEntryByExternalIDParamsBodyExpirationChange(string targetExpiryDate) + : this() + { + this.TargetExpiryDate = targetExpiryDate; + } +} + +class LedgerCreateEntryByExternalIDParamsBodyExpirationChangeFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyExpirationChange FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyExpirationChange.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyVoid, + LedgerCreateEntryByExternalIDParamsBodyVoidFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyVoid : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the block to void. + /// + public required string BlockID + { + get { return JsonModel.GetNotNullClass(this.RawData, "block_id"); } + init { JsonModel.Set(this._rawData, "block_id", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// Can only be specified when `entry_type=void`. The reason for the void. + /// + public ApiEnum? VoidReason + { + get + { + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "void_reason"); + } + init { JsonModel.Set(this._rawData, "void_reason", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + _ = this.BlockID; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"void\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.Metadata; + this.VoidReason?.Validate(); + } + + public LedgerCreateEntryByExternalIDParamsBodyVoid() + { + this.EntryType = JsonSerializer.Deserialize("\"void\""); + } + + public LedgerCreateEntryByExternalIDParamsBodyVoid( + LedgerCreateEntryByExternalIDParamsBodyVoid ledgerCreateEntryByExternalIDParamsBodyVoid + ) + : base(ledgerCreateEntryByExternalIDParamsBodyVoid) { } + + public LedgerCreateEntryByExternalIDParamsBodyVoid( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"void\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyVoid(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyVoid FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class LedgerCreateEntryByExternalIDParamsBodyVoidFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyVoid FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyVoid.FromRawUnchecked(rawData); +} + +/// +/// Can only be specified when `entry_type=void`. The reason for the void. +/// +[JsonConverter(typeof(LedgerCreateEntryByExternalIDParamsBodyVoidVoidReasonConverter))] +public enum LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason +{ + Refund, +} + +sealed class LedgerCreateEntryByExternalIDParamsBodyVoidVoidReasonConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "refund" => LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund, + _ => (LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + LedgerCreateEntryByExternalIDParamsBodyVoidVoidReason.Refund => "refund", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + LedgerCreateEntryByExternalIDParamsBodyAmendment, + LedgerCreateEntryByExternalIDParamsBodyAmendmentFromRaw + >) +)] +public sealed record class LedgerCreateEntryByExternalIDParamsBodyAmendment : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement or void operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the block to reverse a decrement from. + /// + public required string BlockID + { + get { return JsonModel.GetNotNullClass(this.RawData, "block_id"); } + init { JsonModel.Set(this._rawData, "block_id", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + _ = this.BlockID; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"amendment\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.Metadata; + } + + public LedgerCreateEntryByExternalIDParamsBodyAmendment() + { + this.EntryType = JsonSerializer.Deserialize("\"amendment\""); + } + + public LedgerCreateEntryByExternalIDParamsBodyAmendment( + LedgerCreateEntryByExternalIDParamsBodyAmendment ledgerCreateEntryByExternalIDParamsBodyAmendment + ) + : base(ledgerCreateEntryByExternalIDParamsBodyAmendment) { } + + public LedgerCreateEntryByExternalIDParamsBodyAmendment( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"amendment\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryByExternalIDParamsBodyAmendment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryByExternalIDParamsBodyAmendment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class LedgerCreateEntryByExternalIDParamsBodyAmendmentFromRaw + : IFromRawJson +{ + /// + public LedgerCreateEntryByExternalIDParamsBodyAmendment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerCreateEntryByExternalIDParamsBodyAmendment.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/Body.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/Body.cs deleted file mode 100644 index 0b3c3e4d..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/Body.cs +++ /dev/null @@ -1,25 +0,0 @@ -using BodyProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; -using BodyVariants = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Body -{ - internal Body() { } - - public static BodyVariants::Increment Create(BodyProperties::Increment value) => new(value); - - public static BodyVariants::Decrement Create(BodyProperties::Decrement value) => new(value); - - public static BodyVariants::ExpirationChange Create(BodyProperties::ExpirationChange value) => - new(value); - - public static BodyVariants::Void Create(BodyProperties::Void value) => new(value); - - public static BodyVariants::Amendment Create(BodyProperties::Amendment value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Amendment.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Amendment.cs deleted file mode 100644 index bf8f4f58..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Amendment.cs +++ /dev/null @@ -1,150 +0,0 @@ -using AmendmentProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.AmendmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Amendment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement or void operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the block to reverse a decrement from. - /// - public required string BlockID - { - get - { - if (!this.Properties.TryGetValue("block_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "block_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("block_id"); - } - set { this.Properties["block_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required AmendmentProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - _ = this.BlockID; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public Amendment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Amendment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Amendment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/AmendmentProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/AmendmentProperties/EntryType.cs deleted file mode 100644 index 5d718f37..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/AmendmentProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.AmendmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Amendment = new("amendment"); - - readonly string _value = value; - - public enum Value - { - Amendment, - } - - public Value Known() => - _value switch - { - "amendment" => Value.Amendment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Decrement.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Decrement.cs deleted file mode 100644 index bc513951..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Decrement.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DecrementProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.DecrementProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Decrement : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DecrementProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public Decrement() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Decrement(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Decrement FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/DecrementProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/DecrementProperties/EntryType.cs deleted file mode 100644 index 83266bfb..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/DecrementProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.DecrementProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Decrement, - } - - public Value Known() => - _value switch - { - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/ExpirationChange.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/ExpirationChange.cs deleted file mode 100644 index 29355e60..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/ExpirationChange.cs +++ /dev/null @@ -1,183 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using ExpirationChangeProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.ExpirationChangeProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ExpirationChange : Orb::ModelBase, Orb::IFromRaw -{ - public required ExpirationChangeProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A future date (specified in YYYY-MM-DD format) used for expiration change, - /// denoting when credits transferred (as part of a partial block expiration) should expire. - /// - public required System::DateOnly TargetExpiryDate - { - get - { - if (!this.Properties.TryGetValue("target_expiry_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "target_expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["target_expiry_date"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public double? Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the block affected by an expiration_change, used to differentiate - /// between multiple blocks with the same `expiry_date`. - /// - public string? BlockID - { - get - { - if (!this.Properties.TryGetValue("block_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["block_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that identifies the origination credit block to expire - /// - public System::DateTime? ExpiryDate - { - get - { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.EntryType.Validate(); - _ = this.TargetExpiryDate; - _ = this.Amount; - _ = this.BlockID; - _ = this.Currency; - _ = this.Description; - _ = this.ExpiryDate; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public ExpirationChange() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ExpirationChange(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ExpirationChange FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/ExpirationChangeProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/ExpirationChangeProperties/EntryType.cs deleted file mode 100644 index 7c0399c7..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/ExpirationChangeProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.ExpirationChangeProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType ExpirationChange = new("expiration_change"); - - readonly string _value = value; - - public enum Value - { - ExpirationChange, - } - - public Value Known() => - _value switch - { - "expiration_change" => Value.ExpirationChange, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Increment.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Increment.cs deleted file mode 100644 index c759cc5e..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Increment.cs +++ /dev/null @@ -1,204 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using IncrementProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Increment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required IncrementProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that denotes when this credit balance should become - /// available for use. - /// - public System::DateTime? EffectiveDate - { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that denotes when this credit balance should expire. - /// - public System::DateTime? ExpiryDate - { - get - { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Passing `invoice_settings` automatically generates an invoice for the newly - /// added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, - /// as the calculation of the invoice total is done on that basis. - /// - public IncrementProperties::InvoiceSettings? InvoiceSettings - { - get - { - if (!this.Properties.TryGetValue("invoice_settings", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_settings"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Can only be specified when entry_type=increment. How much, in the customer's - /// currency, a customer paid for a single credit in this block - /// - public string? PerUnitCostBasis - { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.Amount; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - _ = this.EffectiveDate; - _ = this.ExpiryDate; - this.InvoiceSettings?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.PerUnitCostBasis; - } - - public Increment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Increment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Increment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/EntryType.cs deleted file mode 100644 index 7f047af8..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Increment = new("increment"); - - readonly string _value = value; - - public enum Value - { - Increment, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettings.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettings.cs deleted file mode 100644 index a5ca5439..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettings.cs +++ /dev/null @@ -1,143 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using InvoiceSettingsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties; - -/// -/// Passing `invoice_settings` automatically generates an invoice for the newly added -/// credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, -/// as the calculation of the invoice total is done on that basis. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceSettings : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Whether the credits purchase invoice should auto collect with the customer's - /// saved payment method. - /// - public required bool AutoCollection - { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. - /// - public required long NetTerms - { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that denotes when this invoice should be dated in the - /// customer's timezone. If not provided, the invoice date will default to the - /// credit block's effective date. - /// - public InvoiceSettingsProperties::InvoiceDate? InvoiceDate - { - get - { - if (!this.Properties.TryGetValue("invoice_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set { this.Properties["invoice_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional memo to display on the invoice. - /// - public string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If true, the new credit block will require that the corresponding invoice is - /// paid before it can be drawn down from. - /// - public bool? RequireSuccessfulPayment - { - get - { - if ( - !this.Properties.TryGetValue( - "require_successful_payment", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["require_successful_payment"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.AutoCollection; - _ = this.NetTerms; - this.InvoiceDate?.Validate(); - _ = this.Memo; - _ = this.RequireSuccessfulPayment; - } - - public InvoiceSettings() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceSettings(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static InvoiceSettings FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDate.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDate.cs deleted file mode 100644 index 23b18551..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDate.cs +++ /dev/null @@ -1,23 +0,0 @@ -using InvoiceDateVariants = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties.InvoiceDateVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; - -/// -/// An ISO 8601 format date that denotes when this invoice should be dated in the -/// customer's timezone. If not provided, the invoice date will default to the credit -/// block's effective date. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class InvoiceDate -{ - internal InvoiceDate() { } - - public static InvoiceDateVariants::Date Create(System::DateOnly value) => new(value); - - public static InvoiceDateVariants::DateTime Create(System::DateTime value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDateVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDateVariants/All.cs deleted file mode 100644 index 04405607..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDateVariants/All.cs +++ /dev/null @@ -1,32 +0,0 @@ -using InvoiceSettingsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties.InvoiceDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Date(System::DateOnly Value) - : InvoiceSettingsProperties::InvoiceDate, - Orb::IVariant -{ - public static Date From(System::DateOnly value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : InvoiceSettingsProperties::InvoiceDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Void.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Void.cs deleted file mode 100644 index 6f3d1d36..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/Void.cs +++ /dev/null @@ -1,164 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using VoidProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.VoidProperties; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Void : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the block to void. - /// - public required string BlockID - { - get - { - if (!this.Properties.TryGetValue("block_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "block_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("block_id"); - } - set { this.Properties["block_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required VoidProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Can only be specified when `entry_type=void`. The reason for the void. - /// - public VoidProperties::VoidReason? VoidReason - { - get - { - if (!this.Properties.TryGetValue("void_reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["void_reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - _ = this.BlockID; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - this.VoidReason?.Validate(); - } - - public Void() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Void(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Void FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/VoidProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/VoidProperties/EntryType.cs deleted file mode 100644 index a2868395..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/VoidProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.VoidProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Void = new("void"); - - readonly string _value = value; - - public enum Value - { - Void, - } - - public Value Known() => - _value switch - { - "void" => Value.Void, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/VoidProperties/VoidReason.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/VoidProperties/VoidReason.cs deleted file mode 100644 index 1a153087..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyProperties/VoidProperties/VoidReason.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties.VoidProperties; - -/// -/// Can only be specified when `entry_type=void`. The reason for the void. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class VoidReason(string value) : Orb::IEnum -{ - public static readonly VoidReason Refund = new("refund"); - - readonly string _value = value; - - public enum Value - { - Refund, - } - - public Value Known() => - _value switch - { - "refund" => Value.Refund, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static VoidReason FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyVariants/All.cs deleted file mode 100644 index a4732b98..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDParamsProperties/BodyVariants/All.cs +++ /dev/null @@ -1,88 +0,0 @@ -using BodyProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyProperties; -using LedgerCreateEntryByExternalIDParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDParamsProperties.BodyVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Increment(BodyProperties::Increment Value) - : LedgerCreateEntryByExternalIDParamsProperties::Body, - Orb::IVariant -{ - public static Increment From(BodyProperties::Increment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Decrement(BodyProperties::Decrement Value) - : LedgerCreateEntryByExternalIDParamsProperties::Body, - Orb::IVariant -{ - public static Decrement From(BodyProperties::Decrement value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ExpirationChange(BodyProperties::ExpirationChange Value) - : LedgerCreateEntryByExternalIDParamsProperties::Body, - Orb::IVariant -{ - public static ExpirationChange From(BodyProperties::ExpirationChange value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Void(BodyProperties::Void Value) - : LedgerCreateEntryByExternalIDParamsProperties::Body, - Orb::IVariant -{ - public static Void From(BodyProperties::Void value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Amendment(BodyProperties::Amendment Value) - : LedgerCreateEntryByExternalIDParamsProperties::Body, - Orb::IVariant -{ - public static Amendment From(BodyProperties::Amendment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponse.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponse.cs index 1e3b2ce9..5b2a6b19 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponse.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponse.cs @@ -1,6 +1,8 @@ -using LedgerCreateEntryByExternalIDResponseVariants = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDResponseVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; +using System = System; namespace Orb.Models.Customers.Credits.Ledger; @@ -8,38 +10,816 @@ namespace Orb.Models.Customers.Credits.Ledger; /// The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid /// credits within Orb. /// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class LedgerCreateEntryByExternalIDResponse +[JsonConverter(typeof(LedgerCreateEntryByExternalIDResponseConverter))] +public record class LedgerCreateEntryByExternalIDResponse { - internal LedgerCreateEntryByExternalIDResponse() { } + public object? Value { get; } = null; - public static LedgerCreateEntryByExternalIDResponseVariants::IncrementLedgerEntry Create( + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + incrementLedgerEntry: (x) => x.ID, + decrementLedgerEntry: (x) => x.ID, + expirationChangeLedgerEntry: (x) => x.ID, + creditBlockExpiryLedgerEntry: (x) => x.ID, + voidLedgerEntry: (x) => x.ID, + voidInitiatedLedgerEntry: (x) => x.ID, + amendmentLedgerEntry: (x) => x.ID + ); + } + } + + public double Amount + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Amount, + decrementLedgerEntry: (x) => x.Amount, + expirationChangeLedgerEntry: (x) => x.Amount, + creditBlockExpiryLedgerEntry: (x) => x.Amount, + voidLedgerEntry: (x) => x.Amount, + voidInitiatedLedgerEntry: (x) => x.Amount, + amendmentLedgerEntry: (x) => x.Amount + ); + } + } + + public System::DateTimeOffset CreatedAt + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreatedAt, + decrementLedgerEntry: (x) => x.CreatedAt, + expirationChangeLedgerEntry: (x) => x.CreatedAt, + creditBlockExpiryLedgerEntry: (x) => x.CreatedAt, + voidLedgerEntry: (x) => x.CreatedAt, + voidInitiatedLedgerEntry: (x) => x.CreatedAt, + amendmentLedgerEntry: (x) => x.CreatedAt + ); + } + } + + public AffectedBlock CreditBlock + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreditBlock, + decrementLedgerEntry: (x) => x.CreditBlock, + expirationChangeLedgerEntry: (x) => x.CreditBlock, + creditBlockExpiryLedgerEntry: (x) => x.CreditBlock, + voidLedgerEntry: (x) => x.CreditBlock, + voidInitiatedLedgerEntry: (x) => x.CreditBlock, + amendmentLedgerEntry: (x) => x.CreditBlock + ); + } + } + + public string Currency + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Currency, + decrementLedgerEntry: (x) => x.Currency, + expirationChangeLedgerEntry: (x) => x.Currency, + creditBlockExpiryLedgerEntry: (x) => x.Currency, + voidLedgerEntry: (x) => x.Currency, + voidInitiatedLedgerEntry: (x) => x.Currency, + amendmentLedgerEntry: (x) => x.Currency + ); + } + } + + public CustomerMinified Customer + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Customer, + decrementLedgerEntry: (x) => x.Customer, + expirationChangeLedgerEntry: (x) => x.Customer, + creditBlockExpiryLedgerEntry: (x) => x.Customer, + voidLedgerEntry: (x) => x.Customer, + voidInitiatedLedgerEntry: (x) => x.Customer, + amendmentLedgerEntry: (x) => x.Customer + ); + } + } + + public string? Description + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Description, + decrementLedgerEntry: (x) => x.Description, + expirationChangeLedgerEntry: (x) => x.Description, + creditBlockExpiryLedgerEntry: (x) => x.Description, + voidLedgerEntry: (x) => x.Description, + voidInitiatedLedgerEntry: (x) => x.Description, + amendmentLedgerEntry: (x) => x.Description + ); + } + } + + public double EndingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.EndingBalance, + decrementLedgerEntry: (x) => x.EndingBalance, + expirationChangeLedgerEntry: (x) => x.EndingBalance, + creditBlockExpiryLedgerEntry: (x) => x.EndingBalance, + voidLedgerEntry: (x) => x.EndingBalance, + voidInitiatedLedgerEntry: (x) => x.EndingBalance, + amendmentLedgerEntry: (x) => x.EndingBalance + ); + } + } + + public long LedgerSequenceNumber + { + get + { + return Match( + incrementLedgerEntry: (x) => x.LedgerSequenceNumber, + decrementLedgerEntry: (x) => x.LedgerSequenceNumber, + expirationChangeLedgerEntry: (x) => x.LedgerSequenceNumber, + creditBlockExpiryLedgerEntry: (x) => x.LedgerSequenceNumber, + voidLedgerEntry: (x) => x.LedgerSequenceNumber, + voidInitiatedLedgerEntry: (x) => x.LedgerSequenceNumber, + amendmentLedgerEntry: (x) => x.LedgerSequenceNumber + ); + } + } + + public double StartingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.StartingBalance, + decrementLedgerEntry: (x) => x.StartingBalance, + expirationChangeLedgerEntry: (x) => x.StartingBalance, + creditBlockExpiryLedgerEntry: (x) => x.StartingBalance, + voidLedgerEntry: (x) => x.StartingBalance, + voidInitiatedLedgerEntry: (x) => x.StartingBalance, + amendmentLedgerEntry: (x) => x.StartingBalance + ); + } + } + + public System::DateTimeOffset? NewBlockExpiryDate + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (x) => x.NewBlockExpiryDate, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (_) => null, + voidInitiatedLedgerEntry: (x) => x.NewBlockExpiryDate, + amendmentLedgerEntry: (_) => null + ); + } + } + + public double? VoidAmount + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidAmount, + voidInitiatedLedgerEntry: (x) => x.VoidAmount, + amendmentLedgerEntry: (_) => null + ); + } + } + + public string? VoidReason + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidReason, + voidInitiatedLedgerEntry: (x) => x.VoidReason, + amendmentLedgerEntry: (_) => null + ); + } + } + + public LedgerCreateEntryByExternalIDResponse( + IncrementLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse( + DecrementLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse( + ExpirationChangeLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse( + CreditBlockExpiryLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse(VoidLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse( + VoidInitiatedLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse( + AmendmentLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryByExternalIDResponse(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickIncrementLedgerEntry(out var value)) { + /// // `value` is of type `IncrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickIncrementLedgerEntry([NotNullWhen(true)] out IncrementLedgerEntry? value) + { + value = this.Value as IncrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDecrementLedgerEntry(out var value)) { + /// // `value` is of type `DecrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDecrementLedgerEntry([NotNullWhen(true)] out DecrementLedgerEntry? value) + { + value = this.Value as DecrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickExpirationChangeLedgerEntry(out var value)) { + /// // `value` is of type `ExpirationChangeLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickExpirationChangeLedgerEntry( + [NotNullWhen(true)] out ExpirationChangeLedgerEntry? value + ) + { + value = this.Value as ExpirationChangeLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCreditBlockExpiryLedgerEntry(out var value)) { + /// // `value` is of type `CreditBlockExpiryLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCreditBlockExpiryLedgerEntry( + [NotNullWhen(true)] out CreditBlockExpiryLedgerEntry? value + ) + { + value = this.Value as CreditBlockExpiryLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidLedgerEntry(out var value)) { + /// // `value` is of type `VoidLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidLedgerEntry([NotNullWhen(true)] out VoidLedgerEntry? value) + { + value = this.Value as VoidLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidInitiatedLedgerEntry(out var value)) { + /// // `value` is of type `VoidInitiatedLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidInitiatedLedgerEntry( + [NotNullWhen(true)] out VoidInitiatedLedgerEntry? value + ) + { + value = this.Value as VoidInitiatedLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmendmentLedgerEntry(out var value)) { + /// // `value` is of type `AmendmentLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmendmentLedgerEntry([NotNullWhen(true)] out AmendmentLedgerEntry? value) + { + value = this.Value as AmendmentLedgerEntry; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action incrementLedgerEntry, + System::Action decrementLedgerEntry, + System::Action expirationChangeLedgerEntry, + System::Action creditBlockExpiryLedgerEntry, + System::Action voidLedgerEntry, + System::Action voidInitiatedLedgerEntry, + System::Action amendmentLedgerEntry + ) + { + switch (this.Value) + { + case IncrementLedgerEntry value: + incrementLedgerEntry(value); + break; + case DecrementLedgerEntry value: + decrementLedgerEntry(value); + break; + case ExpirationChangeLedgerEntry value: + expirationChangeLedgerEntry(value); + break; + case CreditBlockExpiryLedgerEntry value: + creditBlockExpiryLedgerEntry(value); + break; + case VoidLedgerEntry value: + voidLedgerEntry(value); + break; + case VoidInitiatedLedgerEntry value: + voidInitiatedLedgerEntry(value); + break; + case AmendmentLedgerEntry value: + amendmentLedgerEntry(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDResponse" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func incrementLedgerEntry, + System::Func decrementLedgerEntry, + System::Func expirationChangeLedgerEntry, + System::Func creditBlockExpiryLedgerEntry, + System::Func voidLedgerEntry, + System::Func voidInitiatedLedgerEntry, + System::Func amendmentLedgerEntry + ) + { + return this.Value switch + { + IncrementLedgerEntry value => incrementLedgerEntry(value), + DecrementLedgerEntry value => decrementLedgerEntry(value), + ExpirationChangeLedgerEntry value => expirationChangeLedgerEntry(value), + CreditBlockExpiryLedgerEntry value => creditBlockExpiryLedgerEntry(value), + VoidLedgerEntry value => voidLedgerEntry(value), + VoidInitiatedLedgerEntry value => voidInitiatedLedgerEntry(value), + AmendmentLedgerEntry value => amendmentLedgerEntry(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDResponse" + ), + }; + } + + public static implicit operator LedgerCreateEntryByExternalIDResponse( IncrementLedgerEntry value ) => new(value); - public static LedgerCreateEntryByExternalIDResponseVariants::DecrementLedgerEntry Create( + public static implicit operator LedgerCreateEntryByExternalIDResponse( DecrementLedgerEntry value ) => new(value); - public static LedgerCreateEntryByExternalIDResponseVariants::ExpirationChangeLedgerEntry Create( + public static implicit operator LedgerCreateEntryByExternalIDResponse( ExpirationChangeLedgerEntry value ) => new(value); - public static LedgerCreateEntryByExternalIDResponseVariants::CreditBlockExpiryLedgerEntry Create( + public static implicit operator LedgerCreateEntryByExternalIDResponse( CreditBlockExpiryLedgerEntry value ) => new(value); - public static LedgerCreateEntryByExternalIDResponseVariants::VoidLedgerEntry Create( - VoidLedgerEntry value - ) => new(value); + public static implicit operator LedgerCreateEntryByExternalIDResponse(VoidLedgerEntry value) => + new(value); - public static LedgerCreateEntryByExternalIDResponseVariants::VoidInitiatedLedgerEntry Create( + public static implicit operator LedgerCreateEntryByExternalIDResponse( VoidInitiatedLedgerEntry value ) => new(value); - public static LedgerCreateEntryByExternalIDResponseVariants::AmendmentLedgerEntry Create( + public static implicit operator LedgerCreateEntryByExternalIDResponse( AmendmentLedgerEntry value ) => new(value); - public abstract void Validate(); + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryByExternalIDResponse" + ); + } + this.Switch( + (incrementLedgerEntry) => incrementLedgerEntry.Validate(), + (decrementLedgerEntry) => decrementLedgerEntry.Validate(), + (expirationChangeLedgerEntry) => expirationChangeLedgerEntry.Validate(), + (creditBlockExpiryLedgerEntry) => creditBlockExpiryLedgerEntry.Validate(), + (voidLedgerEntry) => voidLedgerEntry.Validate(), + (voidInitiatedLedgerEntry) => voidInitiatedLedgerEntry.Validate(), + (amendmentLedgerEntry) => amendmentLedgerEntry.Validate() + ); + } + + public virtual bool Equals(LedgerCreateEntryByExternalIDResponse? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerCreateEntryByExternalIDResponseConverter + : JsonConverter +{ + public override LedgerCreateEntryByExternalIDResponse? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? entryType; + try + { + entryType = element.GetProperty("entry_type").GetString(); + } + catch + { + entryType = null; + } + + switch (entryType) + { + case "increment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "decrement": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "expiration_change": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "credit_block_expiry": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void_initiated": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amendment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new LedgerCreateEntryByExternalIDResponse(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryByExternalIDResponse value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponseVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponseVariants/All.cs deleted file mode 100644 index 978c6a4d..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryByExternalIDResponseVariants/All.cs +++ /dev/null @@ -1,134 +0,0 @@ -using Ledger = Orb.Models.Customers.Credits.Ledger; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryByExternalIDResponseVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class IncrementLedgerEntry(Ledger::IncrementLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static IncrementLedgerEntry From(Ledger::IncrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class DecrementLedgerEntry(Ledger::DecrementLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static DecrementLedgerEntry From(Ledger::DecrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ExpirationChangeLedgerEntry(Ledger::ExpirationChangeLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static ExpirationChangeLedgerEntry From(Ledger::ExpirationChangeLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - CreditBlockExpiryLedgerEntry, - Ledger::CreditBlockExpiryLedgerEntry - >) -)] -public sealed record class CreditBlockExpiryLedgerEntry(Ledger::CreditBlockExpiryLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static CreditBlockExpiryLedgerEntry From(Ledger::CreditBlockExpiryLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidLedgerEntry(Ledger::VoidLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static VoidLedgerEntry From(Ledger::VoidLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidInitiatedLedgerEntry(Ledger::VoidInitiatedLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static VoidInitiatedLedgerEntry From(Ledger::VoidInitiatedLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmendmentLedgerEntry(Ledger::AmendmentLedgerEntry Value) - : Ledger::LedgerCreateEntryByExternalIDResponse, - Orb::IVariant -{ - public static AmendmentLedgerEntry From(Ledger::AmendmentLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParams.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParams.cs index 436683d2..694cffb7 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParams.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using LedgerCreateEntryParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Customers.Credits.Ledger; @@ -13,128 +16,2236 @@ namespace Orb.Models.Customers.Credits.Ledger; /// balance. This can be used to increment balance, deduct credits, and change the /// expiry date of existing credits. /// -/// ## Effects of adding a ledger entry 1. After calling this endpoint, [Fetch Credit -/// Balance](fetch-customer-credits) will return a credit block that represents +/// ## Effects of adding a ledger entry 1. After calling this endpoint, [Fetch +/// Credit Balance](fetch-customer-credits) will return a credit block that represents /// the changes (i.e. balance changes or transfers). 2. A ledger entry will be added /// to the credits ledger for this customer, and therefore returned in the [View /// Credits Ledger](fetch-customer-credits-ledger) response as well as serialized /// in the response to this request. In the case of deductions without a specified /// block, multiple ledger entries may be created if the deduction spans credit /// blocks. 3. If `invoice_settings` is specified, an invoice will be created that -/// reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). +/// reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). /// -/// ## Adding credits Adding credits is done by creating an entry of type `increment`. -/// This requires the caller to specify a number of credits as well as an optional -/// expiry date in `YYYY-MM-DD` format. Orb also recommends specifying a description -/// to assist with auditing. When adding credits, the caller can also specify a -/// cost basis per-credit, to indicate how much in USD a customer paid for a single -/// credit in a block. This can later be used for revenue recognition. +/// ## Adding credits Adding credits is done by creating an entry of type +/// `increment`. This requires the caller to specify a number of credits as well +/// as an optional expiry date in `YYYY-MM-DD` format. Orb also recommends specifying +/// a description to assist with auditing. When adding credits, the caller can +/// also specify a cost basis per-credit, to indicate how much in USD a customer +/// paid for a single credit in a block. This can later be used for revenue recognition. /// -/// The following snippet illustrates a sample request body to increment credits -/// which will expire in January of 2022. +/// The following snippet illustrates a sample request body to increment credits +/// which will expire in January of 2022. /// -/// ```json { "entry_type": "increment", "amount": 100, "expiry_date": "2022-12-28", -/// "per_unit_cost_basis": "0.20", "description": "Purchased 100 credits" } ``` +/// ```json { "entry_type": "increment", "amount": 100, "expiry_date": +/// "2022-12-28", "per_unit_cost_basis": "0.20", "description": "Purchased 100 +/// credits" } ``` /// -/// Note that by default, Orb will always first increment any _negative_ balance in -/// existing blocks before adding the remaining amount to the desired credit block. +/// Note that by default, Orb will always first increment any _negative_ balance +/// in existing blocks before adding the remaining amount to the desired credit block. /// -/// ### Invoicing for credits By default, Orb manipulates the credit ledger but does -/// not charge for credits. However, if you pass `invoice_settings` in the body of -/// this request, Orb will also generate a one-off invoice for the customer for the -/// credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, +/// ### Invoicing for credits By default, Orb manipulates the credit ledger +/// but does not charge for credits. However, if you pass `invoice_settings` in the +/// body of this request, Orb will also generate a one-off invoice for the customer +/// for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, /// since the total charges on the invoice are calculated by multiplying the cost -/// basis with the number of credit units added. +/// basis with the number of credit units added. /// -/// ## Deducting Credits Orb allows you to deduct credits from a customer by creating -/// an entry of type `decrement`. Orb matches the algorithm for automatic deductions -/// for determining which credit blocks to decrement from. In the case that the deduction -/// leads to multiple ledger entries, the response from this endpoint will be the -/// final deduction. Orb also optionally allows specifying a description to assist -/// with auditing. +/// ## Deducting Credits Orb allows you to deduct credits from a customer by +/// creating an entry of type `decrement`. Orb matches the algorithm for automatic +/// deductions for determining which credit blocks to decrement from. In the case +/// that the deduction leads to multiple ledger entries, the response from this endpoint +/// will be the final deduction. Orb also optionally allows specifying a description +/// to assist with auditing. /// -/// The following snippet illustrates a sample request body to decrement credits. +/// The following snippet illustrates a sample request body to decrement credits. /// -/// ```json { "entry_type": "decrement", "amount": 20, "description": "Removing -/// excess credits" } ``` +/// ```json { "entry_type": "decrement", "amount": 20, "description": +/// "Removing excess credits" } ``` /// -/// ## Changing credits expiry If you'd like to change when existing credits expire, -/// you should create a ledger entry of type `expiration_change`. For this entry, -/// the required parameter `expiry_date` identifies the _originating_ block, and the -/// required parameter `target_expiry_date` identifies when the transferred credits -/// should now expire. A new credit block will be created with expiry date `target_expiry_date`, -/// with the same cost basis data as the original credit block, if present. +/// ## Changing credits expiry If you'd like to change when existing credits +/// expire, you should create a ledger entry of type `expiration_change`. For this +/// entry, the required parameter `expiry_date` identifies the _originating_ block, +/// and the required parameter `target_expiry_date` identifies when the transferred +/// credits should now expire. A new credit block will be created with expiry date +/// `target_expiry_date`, with the same cost basis data as the original credit block, +/// if present. /// -/// Note that the balance of the block with the given `expiry_date` must be at least -/// equal to the desired transfer amount determined by the `amount` parameter. +/// Note that the balance of the block with the given `expiry_date` must be +/// at least equal to the desired transfer amount determined by the `amount` parameter. /// -/// The following snippet illustrates a sample request body to extend the expiration -/// date of credits by one year: +/// The following snippet illustrates a sample request body to extend the expiration +/// date of credits by one year: /// -/// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": +/// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": /// "2022-12-28", "block_id": "UiUhFWeLHPrBY4Ad", "target_expiry_date": "2023-12-28", -/// "description": "Extending credit validity" } ``` +/// "description": "Extending credit validity" } ``` /// -/// ## Voiding credits +/// ## Voiding credits /// -/// If you'd like to void a credit block, create a ledger entry of type `void`. For -/// this entry, `block_id` is required to identify the block, and `amount` indicates +/// If you'd like to void a credit block, create a ledger entry of type `void`. +/// For this entry, `block_id` is required to identify the block, and `amount` indicates /// how many credits to void, up to the block's initial balance. Pass in a `void_reason` -/// of `refund` if the void is due to a refund. +/// of `refund` if the void is due to a refund. /// -/// ## Amendment +/// ## Amendment /// -/// If you'd like to undo a decrement on a credit block, create a ledger entry of -/// type `amendment`. For this entry, `block_id` is required to identify the block +/// If you'd like to undo a decrement on a credit block, create a ledger entry +/// of type `amendment`. For this entry, `block_id` is required to identify the block /// that was originally decremented from, and `amount` indicates how many credits -/// to return to the customer, up to the block's initial balance. +/// to return to the customer, up to the block's initial balance. /// -public sealed record class LedgerCreateEntryParams : Orb::ParamsBase +public sealed record class LedgerCreateEntryParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string CustomerID; + public string? CustomerID { get; init; } - public required LedgerCreateEntryParamsProperties::Body Body + public required Body Body { - get - { - if (!this.BodyProperties.TryGetValue("body", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("body", "Missing required argument"); + get { return JsonModel.GetNotNullClass(this.RawBodyData, "body"); } + init { JsonModel.Set(this._rawBodyData, "body", value); } + } - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("body"); - } - set { this.BodyProperties["body"] = Json::JsonSerializer.SerializeToElement(value); } + public LedgerCreateEntryParams() { } + + public LedgerCreateEntryParams(LedgerCreateEntryParams ledgerCreateEntryParams) + : base(ledgerCreateEntryParams) + { + this._rawBodyData = [.. ledgerCreateEntryParams._rawBodyData]; + } + + public LedgerCreateEntryParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerCreateEntryParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerCreateEntryParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/credits/ledger_entry", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +[JsonConverter(typeof(BodyConverter))] +public record class Body +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public double? Amount + { + get + { + return Match( + increment: (x) => x.Amount, + decrement: (x) => x.Amount, + expirationChange: (x) => x.Amount, + void1: (x) => x.Amount, + amendment: (x) => x.Amount + ); + } + } + + public JsonElement EntryType + { + get + { + return Match( + increment: (x) => x.EntryType, + decrement: (x) => x.EntryType, + expirationChange: (x) => x.EntryType, + void1: (x) => x.EntryType, + amendment: (x) => x.EntryType + ); + } + } + + public string? Currency + { + get + { + return Match( + increment: (x) => x.Currency, + decrement: (x) => x.Currency, + expirationChange: (x) => x.Currency, + void1: (x) => x.Currency, + amendment: (x) => x.Currency + ); + } + } + + public string? Description + { + get + { + return Match( + increment: (x) => x.Description, + decrement: (x) => x.Description, + expirationChange: (x) => x.Description, + void1: (x) => x.Description, + amendment: (x) => x.Description + ); + } + } + + public System::DateTimeOffset? ExpiryDate + { + get + { + return Match( + increment: (x) => x.ExpiryDate, + decrement: (_) => null, + expirationChange: (x) => x.ExpiryDate, + void1: (_) => null, + amendment: (_) => null + ); + } + } + + public string? BlockID + { + get + { + return Match( + increment: (_) => null, + decrement: (_) => null, + expirationChange: (x) => x.BlockID, + void1: (x) => x.BlockID, + amendment: (x) => x.BlockID + ); + } + } + + public Body(Increment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(Decrement value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(ExpirationChange value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(Void value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(Amendment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickIncrement(out var value)) { + /// // `value` is of type `Increment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickIncrement([NotNullWhen(true)] out Increment? value) + { + value = this.Value as Increment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDecrement(out var value)) { + /// // `value` is of type `Decrement` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDecrement([NotNullWhen(true)] out Decrement? value) + { + value = this.Value as Decrement; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickExpirationChange(out var value)) { + /// // `value` is of type `ExpirationChange` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickExpirationChange([NotNullWhen(true)] out ExpirationChange? value) + { + value = this.Value as ExpirationChange; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoid(out var value)) { + /// // `value` is of type `Void` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoid([NotNullWhen(true)] out Void? value) + { + value = this.Value as Void; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmendment(out var value)) { + /// // `value` is of type `Amendment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmendment([NotNullWhen(true)] out Amendment? value) + { + value = this.Value as Amendment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (Increment value) => {...}, + /// (Decrement value) => {...}, + /// (ExpirationChange value) => {...}, + /// (Void value) => {...}, + /// (Amendment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action increment, + System::Action decrement, + System::Action expirationChange, + System::Action void1, + System::Action amendment + ) + { + switch (this.Value) + { + case Increment value: + increment(value); + break; + case Decrement value: + decrement(value); + break; + case ExpirationChange value: + expirationChange(value); + break; + case Void value: + void1(value); + break; + case Amendment value: + amendment(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Body"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (Increment value) => {...}, + /// (Decrement value) => {...}, + /// (ExpirationChange value) => {...}, + /// (Void value) => {...}, + /// (Amendment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func increment, + System::Func decrement, + System::Func expirationChange, + System::Func void1, + System::Func amendment + ) + { + return this.Value switch + { + Increment value => increment(value), + Decrement value => decrement(value), + ExpirationChange value => expirationChange(value), + Void value => void1(value), + Amendment value => amendment(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Body"), + }; + } + + public static implicit operator Body(Increment value) => new(value); + + public static implicit operator Body(Decrement value) => new(value); + + public static implicit operator Body(ExpirationChange value) => new(value); + + public static implicit operator Body(Void value) => new(value); + + public static implicit operator Body(Amendment value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Body"); + } + this.Switch( + (increment) => increment.Validate(), + (decrement) => decrement.Validate(), + (expirationChange) => expirationChange.Validate(), + (void1) => void1.Validate(), + (amendment) => amendment.Validate() + ); + } + + public virtual bool Equals(Body? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class BodyConverter : JsonConverter +{ + public override Body? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? entryType; + try + { + entryType = element.GetProperty("entry_type").GetString(); + } + catch + { + entryType = null; + } + + switch (entryType) + { + case "increment": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "decrement": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "expiration_change": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amendment": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new Body(element); + } + } + } + + public override void Write(Utf8JsonWriter writer, Body value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Increment : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// An ISO 8601 format date that denotes when this credit balance should become + /// available for use. + /// + public System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); + } + init { JsonModel.Set(this._rawData, "effective_date", value); } + } + + /// + /// An ISO 8601 format date that denotes when this credit balance should expire. + /// + public System::DateTimeOffset? ExpiryDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); + } + init { JsonModel.Set(this._rawData, "expiry_date", value); } + } + + /// + /// Optional filter to specify which items this credit block applies to. If not + /// specified, the block will apply to all items for the pricing unit. + /// + public IReadOnlyList? Filters + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Passing `invoice_settings` automatically generates an invoice for the newly + /// added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, + /// as the calculation of the invoice total is done on that basis. + /// + public InvoiceSettings? InvoiceSettings + { + get + { + return JsonModel.GetNullableClass(this.RawData, "invoice_settings"); + } + init { JsonModel.Set(this._rawData, "invoice_settings", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// Can only be specified when entry_type=increment. How much, in the customer's + /// currency, a customer paid for a single credit in this block + /// + public string? PerUnitCostBasis + { + get { return JsonModel.GetNullableClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + /// + public override void Validate() { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + _ = this.Amount; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"increment\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.EffectiveDate; + _ = this.ExpiryDate; + foreach (var item in this.Filters ?? []) + { + item.Validate(); + } + this.InvoiceSettings?.Validate(); + _ = this.Metadata; + _ = this.PerUnitCostBasis; + } + + public Increment() + { + this.EntryType = JsonSerializer.Deserialize("\"increment\""); + } + + public Increment(Increment increment) + : base(increment) { } + + public Increment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"increment\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Increment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Increment FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Increment(double amount) + : this() + { + this.Amount = amount; + } +} + +class IncrementFromRaw : IFromRawJson +{ + /// + public Increment FromRawUnchecked(IReadOnlyDictionary rawData) => + Increment.FromRawUnchecked(rawData); +} + +/// +/// A PriceFilter that only allows item_id field for block filters. +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Customers.Credits.Ledger.Filter, + global::Orb.Models.Customers.Credits.Ledger.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// The property of the price the block applies to. Only item_id is supported. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public Filter() { } + + public Filter(global::Orb.Models.Customers.Credits.Ledger.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Customers.Credits.Ledger.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Customers.Credits.Ledger.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Customers.Credits.Ledger.Filter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price the block applies to. Only item_id is supported. +/// +[JsonConverter(typeof(global::Orb.Models.Customers.Credits.Ledger.FieldConverter))] +public enum Field +{ + ItemID, +} + +sealed class FieldConverter : JsonConverter +{ + public override global::Orb.Models.Customers.Credits.Ledger.Field Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "item_id" => global::Orb.Models.Customers.Credits.Ledger.Field.ItemID, + _ => (global::Orb.Models.Customers.Credits.Ledger.Field)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.Credits.Ledger.Field value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.Credits.Ledger.Field.ItemID => "item_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(global::Orb.Models.Customers.Credits.Ledger.OperatorConverter))] +public enum Operator +{ + Includes, + Excludes, +} + +sealed class OperatorConverter : JsonConverter +{ + public override global::Orb.Models.Customers.Credits.Ledger.Operator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => global::Orb.Models.Customers.Credits.Ledger.Operator.Includes, + "excludes" => global::Orb.Models.Customers.Credits.Ledger.Operator.Excludes, + _ => (global::Orb.Models.Customers.Credits.Ledger.Operator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Customers.Credits.Ledger.Operator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Customers.Credits.Ledger.Operator.Includes => "includes", + global::Orb.Models.Customers.Credits.Ledger.Operator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Passing `invoice_settings` automatically generates an invoice for the newly added +/// credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, +/// as the calculation of the invoice total is done on that basis. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceSettings : JsonModel +{ + /// + /// Whether the credits purchase invoice should auto collect with the customer's + /// saved payment method. + /// + public required bool AutoCollection + { + get { return JsonModel.GetNotNullStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } + } + + /// + /// An optional custom due date for the invoice. If not set, the due date will + /// be calculated based on the `net_terms` value. + /// + public CustomDueDate? CustomDueDate + { + get { return JsonModel.GetNullableClass(this.RawData, "custom_due_date"); } + init { JsonModel.Set(this._rawData, "custom_due_date", value); } + } + + /// + /// An ISO 8601 format date that denotes when this invoice should be dated in + /// the customer's timezone. If not provided, the invoice date will default to + /// the credit block's effective date. + /// + public InvoiceDate? InvoiceDate + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_date"); } + init { JsonModel.Set(this._rawData, "invoice_date", value); } + } + + /// + /// The ID of the Item to be used for the invoice line item. If not provided, + /// a default 'Credits' item will be used. + /// + public string? ItemID + { + get { return JsonModel.GetNullableClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// An optional memo to display on the invoice. + /// + public string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + /// + /// The net terms determines the due date of the invoice. Due date is calculated + /// based on the invoice or issuance date, depending on the account's configured + /// due date calculation method. A value of '0' here represents that the invoice + /// is due on issue, whereas a value of '30' represents that the customer has + /// 30 days to pay the invoice. Do not set this field if you want to set a custom + /// due date. + /// + public long? NetTerms + { + get { return JsonModel.GetNullableStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } + } + + /// + /// If true, the new credit block will require that the corresponding invoice + /// is paid before it can be drawn down from. + /// + public bool? RequireSuccessfulPayment + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "require_successful_payment"); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "require_successful_payment", value); + } + } + + /// + public override void Validate() + { + _ = this.AutoCollection; + this.CustomDueDate?.Validate(); + this.InvoiceDate?.Validate(); + _ = this.ItemID; + _ = this.Memo; + _ = this.NetTerms; + _ = this.RequireSuccessfulPayment; + } + + public InvoiceSettings() { } + + public InvoiceSettings(InvoiceSettings invoiceSettings) + : base(invoiceSettings) { } + + public InvoiceSettings(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceSettings(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceSettings FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public InvoiceSettings(bool autoCollection) + : this() + { + this.AutoCollection = autoCollection; + } +} + +class InvoiceSettingsFromRaw : IFromRawJson +{ + /// + public InvoiceSettings FromRawUnchecked(IReadOnlyDictionary rawData) => + InvoiceSettings.FromRawUnchecked(rawData); +} + +/// +/// An optional custom due date for the invoice. If not set, the due date will be +/// calculated based on the `net_terms` value. +/// +[JsonConverter(typeof(CustomDueDateConverter))] +public record class CustomDueDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CustomDueDate(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public CustomDueDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public CustomDueDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CustomDueDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @date, + System::Func @dateTime + ) + { + return this.Value switch + { + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CustomDueDate" + ), + }; + } + + public static implicit operator CustomDueDate(string value) => new(value); + + public static implicit operator CustomDueDate(System::DateTimeOffset value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of CustomDueDate"); + } + } + + public virtual bool Equals(CustomDueDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CustomDueDateConverter : JsonConverter +{ + public override CustomDueDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + CustomDueDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +/// +/// An ISO 8601 format date that denotes when this invoice should be dated in the +/// customer's timezone. If not provided, the invoice date will default to the credit +/// block's effective date. +/// +[JsonConverter(typeof(InvoiceDateConverter))] +public record class InvoiceDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public InvoiceDate(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of InvoiceDate"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @date, + System::Func @dateTime + ) + { + return this.Value switch + { + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of InvoiceDate"), + }; + } + + public static implicit operator InvoiceDate(string value) => new(value); + + public static implicit operator InvoiceDate(System::DateTimeOffset value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of InvoiceDate"); + } + } + + public virtual bool Equals(InvoiceDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class InvoiceDateConverter : JsonConverter +{ + public override InvoiceDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Decrement : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"decrement\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.Metadata; + } + + public Decrement() + { + this.EntryType = JsonSerializer.Deserialize("\"decrement\""); + } + + public Decrement(Decrement decrement) + : base(decrement) { } + + public Decrement(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"decrement\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Decrement(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Decrement FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Decrement(double amount) + : this() + { + this.Amount = amount; + } +} + +class DecrementFromRaw : IFromRawJson +{ + /// + public Decrement FromRawUnchecked(IReadOnlyDictionary rawData) => + Decrement.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ExpirationChange : JsonModel +{ + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// A future date (specified in YYYY-MM-DD format) used for expiration change, + /// denoting when credits transferred (as part of a partial block expiration) + /// should expire. + /// + public required string TargetExpiryDate + { + get { return JsonModel.GetNotNullClass(this.RawData, "target_expiry_date"); } + init { JsonModel.Set(this._rawData, "target_expiry_date", value); } + } + + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public double? Amount + { + get { return JsonModel.GetNullableStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the block affected by an expiration_change, used to differentiate + /// between multiple blocks with the same `expiry_date`. + /// + public string? BlockID + { + get { return JsonModel.GetNullableClass(this.RawData, "block_id"); } + init { JsonModel.Set(this._rawData, "block_id", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// An ISO 8601 format date that identifies the origination credit block to expire + /// + public System::DateTimeOffset? ExpiryDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "expiry_date"); + } + init { JsonModel.Set(this._rawData, "expiry_date", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"expiration_change\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.TargetExpiryDate; + _ = this.Amount; + _ = this.BlockID; + _ = this.Currency; + _ = this.Description; + _ = this.ExpiryDate; + _ = this.Metadata; + } + + public ExpirationChange() + { + this.EntryType = JsonSerializer.Deserialize("\"expiration_change\""); + } + + public ExpirationChange(ExpirationChange expirationChange) + : base(expirationChange) { } + + public ExpirationChange(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"expiration_change\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExpirationChange(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ExpirationChange FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ExpirationChange(string targetExpiryDate) + : this() + { + this.TargetExpiryDate = targetExpiryDate; + } +} + +class ExpirationChangeFromRaw : IFromRawJson +{ + /// + public ExpirationChange FromRawUnchecked(IReadOnlyDictionary rawData) => + ExpirationChange.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Void : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement, void, or undo operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the block to void. + /// + public required string BlockID + { + get { return JsonModel.GetNotNullClass(this.RawData, "block_id"); } + init { JsonModel.Set(this._rawData, "block_id", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// Can only be specified when `entry_type=void`. The reason for the void. + /// + public ApiEnum? VoidReason + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "void_reason" + ); + } + init { JsonModel.Set(this._rawData, "void_reason", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + _ = this.BlockID; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"void\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.Metadata; + this.VoidReason?.Validate(); + } + + public Void() + { + this.EntryType = JsonSerializer.Deserialize("\"void\""); + } + + public Void(Void void1) + : base(void1) { } + + public Void(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"void\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Void(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Void FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class VoidFromRaw : IFromRawJson +{ + /// + public Void FromRawUnchecked(IReadOnlyDictionary rawData) => + Void.FromRawUnchecked(rawData); +} + +/// +/// Can only be specified when `entry_type=void`. The reason for the void. +/// +[JsonConverter(typeof(VoidReasonConverter))] +public enum VoidReason +{ + Refund, +} + +sealed class VoidReasonConverter : JsonConverter +{ + public override VoidReason Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "refund" => VoidReason.Refund, + _ => (VoidReason)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + VoidReason value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + VoidReason.Refund => "refund", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Amendment : JsonModel +{ + /// + /// The number of credits to effect. Note that this is required for increment, + /// decrement or void operations. + /// + public required double Amount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The ID of the block to reverse a decrement from. + /// + public required string BlockID + { + get { return JsonModel.GetNotNullClass(this.RawData, "block_id"); } + init { JsonModel.Set(this._rawData, "block_id", value); } + } + + public JsonElement EntryType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "entry_type"); } + init { JsonModel.Set(this._rawData, "entry_type", value); } + } + + /// + /// The currency or custom pricing unit to use for this ledger entry. If this + /// is a real-world currency, it must match the customer's invoicing currency. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Optional metadata that can be specified when adding ledger results via the + /// API. For example, this can be used to note an increment refers to trial credits, + /// or for noting corrections as a result of an incident, etc. + /// + public string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + _ = this.Amount; + _ = this.BlockID; + if ( + !JsonElement.DeepEquals( + this.EntryType, + JsonSerializer.Deserialize("\"amendment\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Currency; + _ = this.Description; + _ = this.Metadata; + } + + public Amendment() + { + this.EntryType = JsonSerializer.Deserialize("\"amendment\""); + } + + public Amendment(Amendment amendment) + : base(amendment) { } + + public Amendment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.EntryType = JsonSerializer.Deserialize("\"amendment\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Amendment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Amendment FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AmendmentFromRaw : IFromRawJson +{ + /// + public Amendment FromRawUnchecked(IReadOnlyDictionary rawData) => + Amendment.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/Body.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/Body.cs deleted file mode 100644 index cb0e525b..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/Body.cs +++ /dev/null @@ -1,25 +0,0 @@ -using BodyProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; -using BodyVariants = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Body -{ - internal Body() { } - - public static BodyVariants::Increment Create(BodyProperties::Increment value) => new(value); - - public static BodyVariants::Decrement Create(BodyProperties::Decrement value) => new(value); - - public static BodyVariants::ExpirationChange Create(BodyProperties::ExpirationChange value) => - new(value); - - public static BodyVariants::Void Create(BodyProperties::Void value) => new(value); - - public static BodyVariants::Amendment Create(BodyProperties::Amendment value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Amendment.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Amendment.cs deleted file mode 100644 index 2dd02dae..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Amendment.cs +++ /dev/null @@ -1,150 +0,0 @@ -using AmendmentProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.AmendmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Amendment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement or void operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the block to reverse a decrement from. - /// - public required string BlockID - { - get - { - if (!this.Properties.TryGetValue("block_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "block_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("block_id"); - } - set { this.Properties["block_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required AmendmentProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - _ = this.BlockID; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public Amendment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Amendment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Amendment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/AmendmentProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/AmendmentProperties/EntryType.cs deleted file mode 100644 index 9efb1cbf..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/AmendmentProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.AmendmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Amendment = new("amendment"); - - readonly string _value = value; - - public enum Value - { - Amendment, - } - - public Value Known() => - _value switch - { - "amendment" => Value.Amendment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Decrement.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Decrement.cs deleted file mode 100644 index 854e870a..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Decrement.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DecrementProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.DecrementProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Decrement : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DecrementProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public Decrement() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Decrement(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Decrement FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/DecrementProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/DecrementProperties/EntryType.cs deleted file mode 100644 index a720a3de..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/DecrementProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.DecrementProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Decrement, - } - - public Value Known() => - _value switch - { - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/ExpirationChange.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/ExpirationChange.cs deleted file mode 100644 index b89e3e03..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/ExpirationChange.cs +++ /dev/null @@ -1,183 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using ExpirationChangeProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.ExpirationChangeProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ExpirationChange : Orb::ModelBase, Orb::IFromRaw -{ - public required ExpirationChangeProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A future date (specified in YYYY-MM-DD format) used for expiration change, - /// denoting when credits transferred (as part of a partial block expiration) should expire. - /// - public required System::DateOnly TargetExpiryDate - { - get - { - if (!this.Properties.TryGetValue("target_expiry_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "target_expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["target_expiry_date"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public double? Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the block affected by an expiration_change, used to differentiate - /// between multiple blocks with the same `expiry_date`. - /// - public string? BlockID - { - get - { - if (!this.Properties.TryGetValue("block_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["block_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that identifies the origination credit block to expire - /// - public System::DateTime? ExpiryDate - { - get - { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.EntryType.Validate(); - _ = this.TargetExpiryDate; - _ = this.Amount; - _ = this.BlockID; - _ = this.Currency; - _ = this.Description; - _ = this.ExpiryDate; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public ExpirationChange() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ExpirationChange(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ExpirationChange FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/ExpirationChangeProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/ExpirationChangeProperties/EntryType.cs deleted file mode 100644 index 78e2b0a0..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/ExpirationChangeProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.ExpirationChangeProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType ExpirationChange = new("expiration_change"); - - readonly string _value = value; - - public enum Value - { - ExpirationChange, - } - - public Value Known() => - _value switch - { - "expiration_change" => Value.ExpirationChange, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Increment.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Increment.cs deleted file mode 100644 index b851597d..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Increment.cs +++ /dev/null @@ -1,204 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using IncrementProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Increment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required IncrementProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that denotes when this credit balance should become - /// available for use. - /// - public System::DateTime? EffectiveDate - { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that denotes when this credit balance should expire. - /// - public System::DateTime? ExpiryDate - { - get - { - if (!this.Properties.TryGetValue("expiry_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expiry_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Passing `invoice_settings` automatically generates an invoice for the newly - /// added credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, - /// as the calculation of the invoice total is done on that basis. - /// - public IncrementProperties::InvoiceSettings? InvoiceSettings - { - get - { - if (!this.Properties.TryGetValue("invoice_settings", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_settings"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Can only be specified when entry_type=increment. How much, in the customer's - /// currency, a customer paid for a single credit in this block - /// - public string? PerUnitCostBasis - { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.Amount; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - _ = this.EffectiveDate; - _ = this.ExpiryDate; - this.InvoiceSettings?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.PerUnitCostBasis; - } - - public Increment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Increment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Increment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/EntryType.cs deleted file mode 100644 index b7a800c7..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Increment = new("increment"); - - readonly string _value = value; - - public enum Value - { - Increment, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettings.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettings.cs deleted file mode 100644 index deca99ce..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettings.cs +++ /dev/null @@ -1,143 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using InvoiceSettingsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties; - -/// -/// Passing `invoice_settings` automatically generates an invoice for the newly added -/// credits. If `invoice_settings` is passed, you must specify per_unit_cost_basis, -/// as the calculation of the invoice total is done on that basis. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceSettings : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Whether the credits purchase invoice should auto collect with the customer's - /// saved payment method. - /// - public required bool AutoCollection - { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. - /// - public required long NetTerms - { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date that denotes when this invoice should be dated in the - /// customer's timezone. If not provided, the invoice date will default to the - /// credit block's effective date. - /// - public InvoiceSettingsProperties::InvoiceDate? InvoiceDate - { - get - { - if (!this.Properties.TryGetValue("invoice_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set { this.Properties["invoice_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional memo to display on the invoice. - /// - public string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If true, the new credit block will require that the corresponding invoice is - /// paid before it can be drawn down from. - /// - public bool? RequireSuccessfulPayment - { - get - { - if ( - !this.Properties.TryGetValue( - "require_successful_payment", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["require_successful_payment"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.AutoCollection; - _ = this.NetTerms; - this.InvoiceDate?.Validate(); - _ = this.Memo; - _ = this.RequireSuccessfulPayment; - } - - public InvoiceSettings() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceSettings(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static InvoiceSettings FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDate.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDate.cs deleted file mode 100644 index d9360435..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDate.cs +++ /dev/null @@ -1,23 +0,0 @@ -using InvoiceDateVariants = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties.InvoiceDateVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; - -/// -/// An ISO 8601 format date that denotes when this invoice should be dated in the -/// customer's timezone. If not provided, the invoice date will default to the credit -/// block's effective date. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class InvoiceDate -{ - internal InvoiceDate() { } - - public static InvoiceDateVariants::Date Create(System::DateOnly value) => new(value); - - public static InvoiceDateVariants::DateTime Create(System::DateTime value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDateVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDateVariants/All.cs deleted file mode 100644 index 1949ad83..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/IncrementProperties/InvoiceSettingsProperties/InvoiceDateVariants/All.cs +++ /dev/null @@ -1,32 +0,0 @@ -using InvoiceSettingsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.IncrementProperties.InvoiceSettingsProperties.InvoiceDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Date(System::DateOnly Value) - : InvoiceSettingsProperties::InvoiceDate, - Orb::IVariant -{ - public static Date From(System::DateOnly value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : InvoiceSettingsProperties::InvoiceDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Void.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Void.cs deleted file mode 100644 index 241e839d..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/Void.cs +++ /dev/null @@ -1,164 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using VoidProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.VoidProperties; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Void : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of credits to effect. Note that this is required for increment, - /// decrement, void, or undo operations. - /// - public required double Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of the block to void. - /// - public required string BlockID - { - get - { - if (!this.Properties.TryGetValue("block_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "block_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("block_id"); - } - set { this.Properties["block_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required VoidProperties::EntryType EntryType - { - get - { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); - } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this ledger entry. If this is - /// a real-world currency, it must match the customer's invoicing currency. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Optional metadata that can be specified when adding ledger results via the API. - /// For example, this can be used to note an increment refers to trial credits, - /// or for noting corrections as a result of an incident, etc. - /// - public string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Can only be specified when `entry_type=void`. The reason for the void. - /// - public VoidProperties::VoidReason? VoidReason - { - get - { - if (!this.Properties.TryGetValue("void_reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["void_reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Amount; - _ = this.BlockID; - this.EntryType.Validate(); - _ = this.Currency; - _ = this.Description; - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - this.VoidReason?.Validate(); - } - - public Void() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Void(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Void FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/VoidProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/VoidProperties/EntryType.cs deleted file mode 100644 index d1cfb757..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/VoidProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.VoidProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Void = new("void"); - - readonly string _value = value; - - public enum Value - { - Void, - } - - public Value Known() => - _value switch - { - "void" => Value.Void, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/VoidProperties/VoidReason.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/VoidProperties/VoidReason.cs deleted file mode 100644 index 3f90bda4..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyProperties/VoidProperties/VoidReason.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties.VoidProperties; - -/// -/// Can only be specified when `entry_type=void`. The reason for the void. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class VoidReason(string value) : Orb::IEnum -{ - public static readonly VoidReason Refund = new("refund"); - - readonly string _value = value; - - public enum Value - { - Refund, - } - - public Value Known() => - _value switch - { - "refund" => Value.Refund, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static VoidReason FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyVariants/All.cs deleted file mode 100644 index c4973bb8..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryParamsProperties/BodyVariants/All.cs +++ /dev/null @@ -1,88 +0,0 @@ -using BodyProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyProperties; -using LedgerCreateEntryParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryParamsProperties.BodyVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Increment(BodyProperties::Increment Value) - : LedgerCreateEntryParamsProperties::Body, - Orb::IVariant -{ - public static Increment From(BodyProperties::Increment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Decrement(BodyProperties::Decrement Value) - : LedgerCreateEntryParamsProperties::Body, - Orb::IVariant -{ - public static Decrement From(BodyProperties::Decrement value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ExpirationChange(BodyProperties::ExpirationChange Value) - : LedgerCreateEntryParamsProperties::Body, - Orb::IVariant -{ - public static ExpirationChange From(BodyProperties::ExpirationChange value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Void(BodyProperties::Void Value) - : LedgerCreateEntryParamsProperties::Body, - Orb::IVariant -{ - public static Void From(BodyProperties::Void value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Amendment(BodyProperties::Amendment Value) - : LedgerCreateEntryParamsProperties::Body, - Orb::IVariant -{ - public static Amendment From(BodyProperties::Amendment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponse.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponse.cs index 85cb64d2..1b075fc4 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponse.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponse.cs @@ -1,6 +1,8 @@ -using LedgerCreateEntryResponseVariants = Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryResponseVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; +using System = System; namespace Orb.Models.Customers.Credits.Ledger; @@ -8,38 +10,793 @@ namespace Orb.Models.Customers.Credits.Ledger; /// The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid /// credits within Orb. /// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class LedgerCreateEntryResponse +[JsonConverter(typeof(LedgerCreateEntryResponseConverter))] +public record class LedgerCreateEntryResponse { - internal LedgerCreateEntryResponse() { } + public object? Value { get; } = null; - public static LedgerCreateEntryResponseVariants::IncrementLedgerEntry Create( - IncrementLedgerEntry value - ) => new(value); + JsonElement? _element = null; - public static LedgerCreateEntryResponseVariants::DecrementLedgerEntry Create( - DecrementLedgerEntry value - ) => new(value); + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } - public static LedgerCreateEntryResponseVariants::ExpirationChangeLedgerEntry Create( - ExpirationChangeLedgerEntry value - ) => new(value); + public string ID + { + get + { + return Match( + incrementLedgerEntry: (x) => x.ID, + decrementLedgerEntry: (x) => x.ID, + expirationChangeLedgerEntry: (x) => x.ID, + creditBlockExpiryLedgerEntry: (x) => x.ID, + voidLedgerEntry: (x) => x.ID, + voidInitiatedLedgerEntry: (x) => x.ID, + amendmentLedgerEntry: (x) => x.ID + ); + } + } - public static LedgerCreateEntryResponseVariants::CreditBlockExpiryLedgerEntry Create( - CreditBlockExpiryLedgerEntry value - ) => new(value); + public double Amount + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Amount, + decrementLedgerEntry: (x) => x.Amount, + expirationChangeLedgerEntry: (x) => x.Amount, + creditBlockExpiryLedgerEntry: (x) => x.Amount, + voidLedgerEntry: (x) => x.Amount, + voidInitiatedLedgerEntry: (x) => x.Amount, + amendmentLedgerEntry: (x) => x.Amount + ); + } + } - public static LedgerCreateEntryResponseVariants::VoidLedgerEntry Create( - VoidLedgerEntry value - ) => new(value); + public System::DateTimeOffset CreatedAt + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreatedAt, + decrementLedgerEntry: (x) => x.CreatedAt, + expirationChangeLedgerEntry: (x) => x.CreatedAt, + creditBlockExpiryLedgerEntry: (x) => x.CreatedAt, + voidLedgerEntry: (x) => x.CreatedAt, + voidInitiatedLedgerEntry: (x) => x.CreatedAt, + amendmentLedgerEntry: (x) => x.CreatedAt + ); + } + } - public static LedgerCreateEntryResponseVariants::VoidInitiatedLedgerEntry Create( - VoidInitiatedLedgerEntry value - ) => new(value); + public AffectedBlock CreditBlock + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreditBlock, + decrementLedgerEntry: (x) => x.CreditBlock, + expirationChangeLedgerEntry: (x) => x.CreditBlock, + creditBlockExpiryLedgerEntry: (x) => x.CreditBlock, + voidLedgerEntry: (x) => x.CreditBlock, + voidInitiatedLedgerEntry: (x) => x.CreditBlock, + amendmentLedgerEntry: (x) => x.CreditBlock + ); + } + } - public static LedgerCreateEntryResponseVariants::AmendmentLedgerEntry Create( - AmendmentLedgerEntry value - ) => new(value); + public string Currency + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Currency, + decrementLedgerEntry: (x) => x.Currency, + expirationChangeLedgerEntry: (x) => x.Currency, + creditBlockExpiryLedgerEntry: (x) => x.Currency, + voidLedgerEntry: (x) => x.Currency, + voidInitiatedLedgerEntry: (x) => x.Currency, + amendmentLedgerEntry: (x) => x.Currency + ); + } + } - public abstract void Validate(); + public CustomerMinified Customer + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Customer, + decrementLedgerEntry: (x) => x.Customer, + expirationChangeLedgerEntry: (x) => x.Customer, + creditBlockExpiryLedgerEntry: (x) => x.Customer, + voidLedgerEntry: (x) => x.Customer, + voidInitiatedLedgerEntry: (x) => x.Customer, + amendmentLedgerEntry: (x) => x.Customer + ); + } + } + + public string? Description + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Description, + decrementLedgerEntry: (x) => x.Description, + expirationChangeLedgerEntry: (x) => x.Description, + creditBlockExpiryLedgerEntry: (x) => x.Description, + voidLedgerEntry: (x) => x.Description, + voidInitiatedLedgerEntry: (x) => x.Description, + amendmentLedgerEntry: (x) => x.Description + ); + } + } + + public double EndingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.EndingBalance, + decrementLedgerEntry: (x) => x.EndingBalance, + expirationChangeLedgerEntry: (x) => x.EndingBalance, + creditBlockExpiryLedgerEntry: (x) => x.EndingBalance, + voidLedgerEntry: (x) => x.EndingBalance, + voidInitiatedLedgerEntry: (x) => x.EndingBalance, + amendmentLedgerEntry: (x) => x.EndingBalance + ); + } + } + + public long LedgerSequenceNumber + { + get + { + return Match( + incrementLedgerEntry: (x) => x.LedgerSequenceNumber, + decrementLedgerEntry: (x) => x.LedgerSequenceNumber, + expirationChangeLedgerEntry: (x) => x.LedgerSequenceNumber, + creditBlockExpiryLedgerEntry: (x) => x.LedgerSequenceNumber, + voidLedgerEntry: (x) => x.LedgerSequenceNumber, + voidInitiatedLedgerEntry: (x) => x.LedgerSequenceNumber, + amendmentLedgerEntry: (x) => x.LedgerSequenceNumber + ); + } + } + + public double StartingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.StartingBalance, + decrementLedgerEntry: (x) => x.StartingBalance, + expirationChangeLedgerEntry: (x) => x.StartingBalance, + creditBlockExpiryLedgerEntry: (x) => x.StartingBalance, + voidLedgerEntry: (x) => x.StartingBalance, + voidInitiatedLedgerEntry: (x) => x.StartingBalance, + amendmentLedgerEntry: (x) => x.StartingBalance + ); + } + } + + public System::DateTimeOffset? NewBlockExpiryDate + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (x) => x.NewBlockExpiryDate, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (_) => null, + voidInitiatedLedgerEntry: (x) => x.NewBlockExpiryDate, + amendmentLedgerEntry: (_) => null + ); + } + } + + public double? VoidAmount + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidAmount, + voidInitiatedLedgerEntry: (x) => x.VoidAmount, + amendmentLedgerEntry: (_) => null + ); + } + } + + public string? VoidReason + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidReason, + voidInitiatedLedgerEntry: (x) => x.VoidReason, + amendmentLedgerEntry: (_) => null + ); + } + } + + public LedgerCreateEntryResponse(IncrementLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse(DecrementLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse(ExpirationChangeLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse( + CreditBlockExpiryLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse(VoidLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse(VoidInitiatedLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse(AmendmentLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerCreateEntryResponse(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickIncrementLedgerEntry(out var value)) { + /// // `value` is of type `IncrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickIncrementLedgerEntry([NotNullWhen(true)] out IncrementLedgerEntry? value) + { + value = this.Value as IncrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDecrementLedgerEntry(out var value)) { + /// // `value` is of type `DecrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDecrementLedgerEntry([NotNullWhen(true)] out DecrementLedgerEntry? value) + { + value = this.Value as DecrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickExpirationChangeLedgerEntry(out var value)) { + /// // `value` is of type `ExpirationChangeLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickExpirationChangeLedgerEntry( + [NotNullWhen(true)] out ExpirationChangeLedgerEntry? value + ) + { + value = this.Value as ExpirationChangeLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCreditBlockExpiryLedgerEntry(out var value)) { + /// // `value` is of type `CreditBlockExpiryLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCreditBlockExpiryLedgerEntry( + [NotNullWhen(true)] out CreditBlockExpiryLedgerEntry? value + ) + { + value = this.Value as CreditBlockExpiryLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidLedgerEntry(out var value)) { + /// // `value` is of type `VoidLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidLedgerEntry([NotNullWhen(true)] out VoidLedgerEntry? value) + { + value = this.Value as VoidLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidInitiatedLedgerEntry(out var value)) { + /// // `value` is of type `VoidInitiatedLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidInitiatedLedgerEntry( + [NotNullWhen(true)] out VoidInitiatedLedgerEntry? value + ) + { + value = this.Value as VoidInitiatedLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmendmentLedgerEntry(out var value)) { + /// // `value` is of type `AmendmentLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmendmentLedgerEntry([NotNullWhen(true)] out AmendmentLedgerEntry? value) + { + value = this.Value as AmendmentLedgerEntry; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action incrementLedgerEntry, + System::Action decrementLedgerEntry, + System::Action expirationChangeLedgerEntry, + System::Action creditBlockExpiryLedgerEntry, + System::Action voidLedgerEntry, + System::Action voidInitiatedLedgerEntry, + System::Action amendmentLedgerEntry + ) + { + switch (this.Value) + { + case IncrementLedgerEntry value: + incrementLedgerEntry(value); + break; + case DecrementLedgerEntry value: + decrementLedgerEntry(value); + break; + case ExpirationChangeLedgerEntry value: + expirationChangeLedgerEntry(value); + break; + case CreditBlockExpiryLedgerEntry value: + creditBlockExpiryLedgerEntry(value); + break; + case VoidLedgerEntry value: + voidLedgerEntry(value); + break; + case VoidInitiatedLedgerEntry value: + voidInitiatedLedgerEntry(value); + break; + case AmendmentLedgerEntry value: + amendmentLedgerEntry(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryResponse" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func incrementLedgerEntry, + System::Func decrementLedgerEntry, + System::Func expirationChangeLedgerEntry, + System::Func creditBlockExpiryLedgerEntry, + System::Func voidLedgerEntry, + System::Func voidInitiatedLedgerEntry, + System::Func amendmentLedgerEntry + ) + { + return this.Value switch + { + IncrementLedgerEntry value => incrementLedgerEntry(value), + DecrementLedgerEntry value => decrementLedgerEntry(value), + ExpirationChangeLedgerEntry value => expirationChangeLedgerEntry(value), + CreditBlockExpiryLedgerEntry value => creditBlockExpiryLedgerEntry(value), + VoidLedgerEntry value => voidLedgerEntry(value), + VoidInitiatedLedgerEntry value => voidInitiatedLedgerEntry(value), + AmendmentLedgerEntry value => amendmentLedgerEntry(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryResponse" + ), + }; + } + + public static implicit operator LedgerCreateEntryResponse(IncrementLedgerEntry value) => + new(value); + + public static implicit operator LedgerCreateEntryResponse(DecrementLedgerEntry value) => + new(value); + + public static implicit operator LedgerCreateEntryResponse(ExpirationChangeLedgerEntry value) => + new(value); + + public static implicit operator LedgerCreateEntryResponse(CreditBlockExpiryLedgerEntry value) => + new(value); + + public static implicit operator LedgerCreateEntryResponse(VoidLedgerEntry value) => new(value); + + public static implicit operator LedgerCreateEntryResponse(VoidInitiatedLedgerEntry value) => + new(value); + + public static implicit operator LedgerCreateEntryResponse(AmendmentLedgerEntry value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerCreateEntryResponse" + ); + } + this.Switch( + (incrementLedgerEntry) => incrementLedgerEntry.Validate(), + (decrementLedgerEntry) => decrementLedgerEntry.Validate(), + (expirationChangeLedgerEntry) => expirationChangeLedgerEntry.Validate(), + (creditBlockExpiryLedgerEntry) => creditBlockExpiryLedgerEntry.Validate(), + (voidLedgerEntry) => voidLedgerEntry.Validate(), + (voidInitiatedLedgerEntry) => voidInitiatedLedgerEntry.Validate(), + (amendmentLedgerEntry) => amendmentLedgerEntry.Validate() + ); + } + + public virtual bool Equals(LedgerCreateEntryResponse? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerCreateEntryResponseConverter : JsonConverter +{ + public override LedgerCreateEntryResponse? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? entryType; + try + { + entryType = element.GetProperty("entry_type").GetString(); + } + catch + { + entryType = null; + } + + switch (entryType) + { + case "increment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "decrement": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "expiration_change": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "credit_block_expiry": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void_initiated": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amendment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new LedgerCreateEntryResponse(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + LedgerCreateEntryResponse value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponseVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponseVariants/All.cs deleted file mode 100644 index 8e0e7ed0..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerCreateEntryResponseVariants/All.cs +++ /dev/null @@ -1,134 +0,0 @@ -using Ledger = Orb.Models.Customers.Credits.Ledger; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerCreateEntryResponseVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class IncrementLedgerEntry(Ledger::IncrementLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static IncrementLedgerEntry From(Ledger::IncrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class DecrementLedgerEntry(Ledger::DecrementLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static DecrementLedgerEntry From(Ledger::DecrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ExpirationChangeLedgerEntry(Ledger::ExpirationChangeLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static ExpirationChangeLedgerEntry From(Ledger::ExpirationChangeLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - CreditBlockExpiryLedgerEntry, - Ledger::CreditBlockExpiryLedgerEntry - >) -)] -public sealed record class CreditBlockExpiryLedgerEntry(Ledger::CreditBlockExpiryLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static CreditBlockExpiryLedgerEntry From(Ledger::CreditBlockExpiryLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidLedgerEntry(Ledger::VoidLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static VoidLedgerEntry From(Ledger::VoidLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidInitiatedLedgerEntry(Ledger::VoidInitiatedLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static VoidInitiatedLedgerEntry From(Ledger::VoidInitiatedLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmendmentLedgerEntry(Ledger::AmendmentLedgerEntry Value) - : Ledger::LedgerCreateEntryResponse, - Orb::IVariant -{ - public static AmendmentLedgerEntry From(Ledger::AmendmentLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPage.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPage.cs new file mode 100644 index 00000000..6db5203c --- /dev/null +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPage.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers.Credits; + +namespace Orb.Models.Customers.Credits.Ledger; + +public sealed class LedgerListByExternalIDPage( + ILedgerService service, + LedgerListByExternalIDParams parameters, + LedgerListByExternalIDPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next( + CancellationToken cancellationToken = default + ) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .ListByExternalID(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponse.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponse.cs index 69ea462d..afbd9afc 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponse.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponse.cs @@ -1,52 +1,45 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using LedgerListByExternalIDPageResponseProperties = Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDPageResponseProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LedgerListByExternalIDPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + LedgerListByExternalIDPageResponse, + LedgerListByExternalIDPageResponseFromRaw + >) +)] +public sealed record class LedgerListByExternalIDPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +51,37 @@ public override void Validate() public LedgerListByExternalIDPageResponse() { } + public LedgerListByExternalIDPageResponse( + LedgerListByExternalIDPageResponse ledgerListByExternalIDPageResponse + ) + : base(ledgerListByExternalIDPageResponse) { } + + public LedgerListByExternalIDPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LedgerListByExternalIDPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + LedgerListByExternalIDPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static LedgerListByExternalIDPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class LedgerListByExternalIDPageResponseFromRaw : IFromRawJson +{ + /// + public LedgerListByExternalIDPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerListByExternalIDPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseProperties/Data.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseProperties/Data.cs deleted file mode 100644 index 4409f9a2..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseProperties/Data.cs +++ /dev/null @@ -1,41 +0,0 @@ -using DataVariants = Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDPageResponseProperties.DataVariants; -using Ledger = Orb.Models.Customers.Credits.Ledger; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDPageResponseProperties; - -/// -/// The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid -/// credits within Orb. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Data -{ - internal Data() { } - - public static DataVariants::IncrementLedgerEntry Create(Ledger::IncrementLedgerEntry value) => - new(value); - - public static DataVariants::DecrementLedgerEntry Create(Ledger::DecrementLedgerEntry value) => - new(value); - - public static DataVariants::ExpirationChangeLedgerEntry Create( - Ledger::ExpirationChangeLedgerEntry value - ) => new(value); - - public static DataVariants::CreditBlockExpiryLedgerEntry Create( - Ledger::CreditBlockExpiryLedgerEntry value - ) => new(value); - - public static DataVariants::VoidLedgerEntry Create(Ledger::VoidLedgerEntry value) => new(value); - - public static DataVariants::VoidInitiatedLedgerEntry Create( - Ledger::VoidInitiatedLedgerEntry value - ) => new(value); - - public static DataVariants::AmendmentLedgerEntry Create(Ledger::AmendmentLedgerEntry value) => - new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseProperties/DataVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseProperties/DataVariants/All.cs deleted file mode 100644 index f19a33c2..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDPageResponseProperties/DataVariants/All.cs +++ /dev/null @@ -1,135 +0,0 @@ -using Ledger = Orb.Models.Customers.Credits.Ledger; -using LedgerListByExternalIDPageResponseProperties = Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDPageResponseProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDPageResponseProperties.DataVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class IncrementLedgerEntry(Ledger::IncrementLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static IncrementLedgerEntry From(Ledger::IncrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class DecrementLedgerEntry(Ledger::DecrementLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static DecrementLedgerEntry From(Ledger::DecrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ExpirationChangeLedgerEntry(Ledger::ExpirationChangeLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static ExpirationChangeLedgerEntry From(Ledger::ExpirationChangeLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - CreditBlockExpiryLedgerEntry, - Ledger::CreditBlockExpiryLedgerEntry - >) -)] -public sealed record class CreditBlockExpiryLedgerEntry(Ledger::CreditBlockExpiryLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static CreditBlockExpiryLedgerEntry From(Ledger::CreditBlockExpiryLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidLedgerEntry(Ledger::VoidLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static VoidLedgerEntry From(Ledger::VoidLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidInitiatedLedgerEntry(Ledger::VoidInitiatedLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static VoidInitiatedLedgerEntry From(Ledger::VoidInitiatedLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmendmentLedgerEntry(Ledger::AmendmentLedgerEntry Value) - : LedgerListByExternalIDPageResponseProperties::Data, - Orb::IVariant -{ - public static AmendmentLedgerEntry From(Ledger::AmendmentLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParams.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParams.cs index 830858ca..c8480743 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParams.cs @@ -1,7 +1,11 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using LedgerListByExternalIDParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDParamsProperties; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; @@ -12,133 +16,118 @@ namespace Orb.Models.Customers.Credits.Ledger; /// This [paginated endpoint](/api-reference/pagination) lists these entries, starting /// from the most recent ledger entry. /// -/// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). +/// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). /// -/// There are four major types of modifications to credit balance, detailed below. +/// There are four major types of modifications to credit balance, detailed below. /// -/// ## Increment Credits (which optionally expire on a future date) can be added -/// via the API ([Add Ledger Entry](create-ledger-entry)). The ledger entry for such -/// an action will always contain the total eligible starting and ending balance for -/// the customer at the time the entry was added to the ledger. +/// ## Increment Credits (which optionally expire on a future date) can be +/// added via the API ([Add Ledger Entry](create-ledger-entry)). The ledger entry +/// for such an action will always contain the total eligible starting and ending +/// balance for the customer at the time the entry was added to the ledger. /// -/// ## Decrement Deductions can occur as a result of an API call to create a ledger -/// entry (see [Add Ledger Entry](create-ledger-entry)), or automatically as a result -/// of incurring usage. Both ledger entries present the `decrement` entry type. +/// ## Decrement Deductions can occur as a result of an API call to create +/// a ledger entry (see [Add Ledger Entry](create-ledger-entry)), or automatically +/// as a result of incurring usage. Both ledger entries present the `decrement` entry type. /// -/// As usage for a customer is reported into Orb, credits may be deducted according +/// As usage for a customer is reported into Orb, credits may be deducted according /// to the customer's plan configuration. An automated deduction of this type will /// result in a ledger entry, also with a starting and ending balance. In order to /// provide better tracing capabilities for automatic deductions, Orb always associates /// each automatic deduction with the `event_id` at the time of ingestion, used to /// pinpoint _why_ credit deduction took place and to ensure that credits are never -/// deducted without an associated usage event. +/// deducted without an associated usage event. /// -/// By default, Orb uses an algorithm that automatically deducts from the *soonest +/// By default, Orb uses an algorithm that automatically deducts from the *soonest /// expiring credit block* first in order to ensure that all credits are utilized /// appropriately. As an example, if trial credits with an expiration date of 2 weeks -/// from now are present for a customer, they will be used before any deductions -/// take place from a non-expiring credit block. +/// from now are present for a customer, they will be used before any deductions take +/// place from a non-expiring credit block. /// -/// If there are multiple blocks with the same expiration date, Orb will deduct from -/// the block with the *lower cost basis* first (e.g. trial credits with a \$0 cost -/// basis before paid credits with a \$5.00 cost basis). +/// If there are multiple blocks with the same expiration date, Orb will deduct +/// from the block with the *lower cost basis* first (e.g. trial credits with a \$0 +/// cost basis before paid credits with a \$5.00 cost basis). /// -/// It's also possible for a single usage event's deduction to _span_ credit blocks. -/// In this case, Orb will deduct from the next block, ending at the credit block -/// which consists of unexpiring credits. Each of these deductions will lead to a -/// _separate_ ledger entry, one per credit block that is deducted from. By default, -/// the customer's total credit balance in Orb can be negative as a result of a decrement. +/// It's also possible for a single usage event's deduction to _span_ credit +/// blocks. In this case, Orb will deduct from the next block, ending at the credit +/// block which consists of unexpiring credits. Each of these deductions will lead +/// to a _separate_ ledger entry, one per credit block that is deducted from. By default, +/// the customer's total credit balance in Orb can be negative as a result of a decrement. /// -/// ## Expiration change The expiry of credits can be changed as a result of the -/// API (See [Add Ledger Entry](create-ledger-entry)). This will create a ledger -/// entry that specifies the balance as well as the initial and target expiry dates. +/// ## Expiration change The expiry of credits can be changed as a result of +/// the API (See [Add Ledger Entry](create-ledger-entry)). This will create a ledger +/// entry that specifies the balance as well as the initial and target expiry dates. /// -/// Note that for this entry type, `starting_balance` will equal `ending_balance`, -/// and the `amount` represents the balance transferred. The credit block linked -/// to the ledger entry is the source credit block from which there was an expiration change +/// Note that for this entry type, `starting_balance` will equal `ending_balance`, +/// and the `amount` represents the balance transferred. The credit block linked to +/// the ledger entry is the source credit block from which there was an expiration change. /// -/// ## Credits expiry When a set of credits expire on pre-set expiration date, the -/// customer's balance automatically reflects this change and adds an entry to the -/// ledger indicating this event. Note that credit expiry should always happen close -/// to a date boundary in the customer's timezone. +/// ## Credits expiry When a set of credits expire on pre-set expiration date, +/// the customer's balance automatically reflects this change and adds an entry to +/// the ledger indicating this event. Note that credit expiry should always happen +/// close to a date boundary in the customer's timezone. /// -/// ## Void initiated Credit blocks can be voided via the API. The `amount` on this -/// entry corresponds to the number of credits that were remaining in the block at -/// time of void. `void_reason` will be populated if the void is created with a reason. +/// ## Void initiated Credit blocks can be voided via the API. The `amount` +/// on this entry corresponds to the number of credits that were remaining in the +/// block at time of void. `void_reason` will be populated if the void is created +/// with a reason. /// -/// ## Void When a set of credits is voided, the customer's balance automatically -/// reflects this change and adds an entry to the ledger indicating this event. +/// ## Void When a set of credits is voided, the customer's balance automatically +/// reflects this change and adds an entry to the ledger indicating this event. /// -/// ## Amendment When credits are added to a customer's balance as a result of a -/// correction, this entry will be added to the ledger to indicate the adjustment -/// of credits. +/// ## Amendment When credits are added to a customer's balance as a result +/// of a correction, this entry will be added to the ledger to indicate the adjustment +/// of credits. /// -public sealed record class LedgerListByExternalIDParams : Orb::ParamsBase +public sealed record class LedgerListByExternalIDParams : ParamsBase { - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } - public System::DateTime? CreatedAtGt + public System::DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public System::DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public System::DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public System::DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -146,14 +135,8 @@ public sealed record class LedgerListByExternalIDParams : Orb::ParamsBase /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// @@ -162,45 +145,30 @@ public string? Currency /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } - public LedgerListByExternalIDParamsProperties::EntryStatus? EntryStatus + public ApiEnum? EntryStatus { get { - if (!this.QueryProperties.TryGetValue("entry_status", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.QueryProperties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawQueryData, "entry_status"); } + init { JsonModel.Set(this._rawQueryData, "entry_status", value); } } - public LedgerListByExternalIDParamsProperties::EntryType? EntryType + public ApiEnum? EntryType { get { - if (!this.QueryProperties.TryGetValue("entry_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawQueryData, "entry_type"); } - set { this.QueryProperties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "entry_type", value); } } /// @@ -208,51 +176,187 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } public string? MinimumAmount { - get - { - if (!this.QueryProperties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawQueryData, "minimum_amount"); } + init { JsonModel.Set(this._rawQueryData, "minimum_amount", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); - } + public LedgerListByExternalIDParams() { } + + public LedgerListByExternalIDParams(LedgerListByExternalIDParams ledgerListByExternalIDParams) + : base(ledgerListByExternalIDParams) { } + + public LedgerListByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; } - public override System::Uri Url(Orb::IOrbClient client) +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerListByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerListByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/credits/ledger", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter(typeof(LedgerListByExternalIDParamsEntryStatusConverter))] +public enum LedgerListByExternalIDParamsEntryStatus +{ + Committed, + Pending, +} + +sealed class LedgerListByExternalIDParamsEntryStatusConverter + : JsonConverter +{ + public override LedgerListByExternalIDParamsEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => LedgerListByExternalIDParamsEntryStatus.Committed, + "pending" => LedgerListByExternalIDParamsEntryStatus.Pending, + _ => (LedgerListByExternalIDParamsEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + LedgerListByExternalIDParamsEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + LedgerListByExternalIDParamsEntryStatus.Committed => "committed", + LedgerListByExternalIDParamsEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(LedgerListByExternalIDParamsEntryTypeConverter))] +public enum LedgerListByExternalIDParamsEntryType +{ + Increment, + Decrement, + ExpirationChange, + CreditBlockExpiry, + Void, + VoidInitiated, + Amendment, +} + +sealed class LedgerListByExternalIDParamsEntryTypeConverter + : JsonConverter +{ + public override LedgerListByExternalIDParamsEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => LedgerListByExternalIDParamsEntryType.Increment, + "decrement" => LedgerListByExternalIDParamsEntryType.Decrement, + "expiration_change" => LedgerListByExternalIDParamsEntryType.ExpirationChange, + "credit_block_expiry" => LedgerListByExternalIDParamsEntryType.CreditBlockExpiry, + "void" => LedgerListByExternalIDParamsEntryType.Void, + "void_initiated" => LedgerListByExternalIDParamsEntryType.VoidInitiated, + "amendment" => LedgerListByExternalIDParamsEntryType.Amendment, + _ => (LedgerListByExternalIDParamsEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + LedgerListByExternalIDParamsEntryType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + LedgerListByExternalIDParamsEntryType.Increment => "increment", + LedgerListByExternalIDParamsEntryType.Decrement => "decrement", + LedgerListByExternalIDParamsEntryType.ExpirationChange => "expiration_change", + LedgerListByExternalIDParamsEntryType.CreditBlockExpiry => "credit_block_expiry", + LedgerListByExternalIDParamsEntryType.Void => "void", + LedgerListByExternalIDParamsEntryType.VoidInitiated => "void_initiated", + LedgerListByExternalIDParamsEntryType.Amendment => "amendment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsProperties/EntryStatus.cs deleted file mode 100644 index 3d41c636..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsProperties/EntryType.cs deleted file mode 100644 index 8b56743e..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDParamsProperties/EntryType.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListByExternalIDParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Increment = new("increment"); - - public static readonly EntryType Decrement = new("decrement"); - - public static readonly EntryType ExpirationChange = new("expiration_change"); - - public static readonly EntryType CreditBlockExpiry = new("credit_block_expiry"); - - public static readonly EntryType Void = new("void"); - - public static readonly EntryType VoidInitiated = new("void_initiated"); - - public static readonly EntryType Amendment = new("amendment"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - ExpirationChange, - CreditBlockExpiry, - Void, - VoidInitiated, - Amendment, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - "expiration_change" => Value.ExpirationChange, - "credit_block_expiry" => Value.CreditBlockExpiry, - "void" => Value.Void, - "void_initiated" => Value.VoidInitiated, - "amendment" => Value.Amendment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDResponse.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDResponse.cs new file mode 100644 index 00000000..8285c051 --- /dev/null +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListByExternalIDResponse.cs @@ -0,0 +1,812 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.Credits.Ledger; + +/// +/// The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid +/// credits within Orb. +/// +[JsonConverter(typeof(LedgerListByExternalIDResponseConverter))] +public record class LedgerListByExternalIDResponse +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + incrementLedgerEntry: (x) => x.ID, + decrementLedgerEntry: (x) => x.ID, + expirationChangeLedgerEntry: (x) => x.ID, + creditBlockExpiryLedgerEntry: (x) => x.ID, + voidLedgerEntry: (x) => x.ID, + voidInitiatedLedgerEntry: (x) => x.ID, + amendmentLedgerEntry: (x) => x.ID + ); + } + } + + public double Amount + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Amount, + decrementLedgerEntry: (x) => x.Amount, + expirationChangeLedgerEntry: (x) => x.Amount, + creditBlockExpiryLedgerEntry: (x) => x.Amount, + voidLedgerEntry: (x) => x.Amount, + voidInitiatedLedgerEntry: (x) => x.Amount, + amendmentLedgerEntry: (x) => x.Amount + ); + } + } + + public System::DateTimeOffset CreatedAt + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreatedAt, + decrementLedgerEntry: (x) => x.CreatedAt, + expirationChangeLedgerEntry: (x) => x.CreatedAt, + creditBlockExpiryLedgerEntry: (x) => x.CreatedAt, + voidLedgerEntry: (x) => x.CreatedAt, + voidInitiatedLedgerEntry: (x) => x.CreatedAt, + amendmentLedgerEntry: (x) => x.CreatedAt + ); + } + } + + public AffectedBlock CreditBlock + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreditBlock, + decrementLedgerEntry: (x) => x.CreditBlock, + expirationChangeLedgerEntry: (x) => x.CreditBlock, + creditBlockExpiryLedgerEntry: (x) => x.CreditBlock, + voidLedgerEntry: (x) => x.CreditBlock, + voidInitiatedLedgerEntry: (x) => x.CreditBlock, + amendmentLedgerEntry: (x) => x.CreditBlock + ); + } + } + + public string Currency + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Currency, + decrementLedgerEntry: (x) => x.Currency, + expirationChangeLedgerEntry: (x) => x.Currency, + creditBlockExpiryLedgerEntry: (x) => x.Currency, + voidLedgerEntry: (x) => x.Currency, + voidInitiatedLedgerEntry: (x) => x.Currency, + amendmentLedgerEntry: (x) => x.Currency + ); + } + } + + public CustomerMinified Customer + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Customer, + decrementLedgerEntry: (x) => x.Customer, + expirationChangeLedgerEntry: (x) => x.Customer, + creditBlockExpiryLedgerEntry: (x) => x.Customer, + voidLedgerEntry: (x) => x.Customer, + voidInitiatedLedgerEntry: (x) => x.Customer, + amendmentLedgerEntry: (x) => x.Customer + ); + } + } + + public string? Description + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Description, + decrementLedgerEntry: (x) => x.Description, + expirationChangeLedgerEntry: (x) => x.Description, + creditBlockExpiryLedgerEntry: (x) => x.Description, + voidLedgerEntry: (x) => x.Description, + voidInitiatedLedgerEntry: (x) => x.Description, + amendmentLedgerEntry: (x) => x.Description + ); + } + } + + public double EndingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.EndingBalance, + decrementLedgerEntry: (x) => x.EndingBalance, + expirationChangeLedgerEntry: (x) => x.EndingBalance, + creditBlockExpiryLedgerEntry: (x) => x.EndingBalance, + voidLedgerEntry: (x) => x.EndingBalance, + voidInitiatedLedgerEntry: (x) => x.EndingBalance, + amendmentLedgerEntry: (x) => x.EndingBalance + ); + } + } + + public long LedgerSequenceNumber + { + get + { + return Match( + incrementLedgerEntry: (x) => x.LedgerSequenceNumber, + decrementLedgerEntry: (x) => x.LedgerSequenceNumber, + expirationChangeLedgerEntry: (x) => x.LedgerSequenceNumber, + creditBlockExpiryLedgerEntry: (x) => x.LedgerSequenceNumber, + voidLedgerEntry: (x) => x.LedgerSequenceNumber, + voidInitiatedLedgerEntry: (x) => x.LedgerSequenceNumber, + amendmentLedgerEntry: (x) => x.LedgerSequenceNumber + ); + } + } + + public double StartingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.StartingBalance, + decrementLedgerEntry: (x) => x.StartingBalance, + expirationChangeLedgerEntry: (x) => x.StartingBalance, + creditBlockExpiryLedgerEntry: (x) => x.StartingBalance, + voidLedgerEntry: (x) => x.StartingBalance, + voidInitiatedLedgerEntry: (x) => x.StartingBalance, + amendmentLedgerEntry: (x) => x.StartingBalance + ); + } + } + + public System::DateTimeOffset? NewBlockExpiryDate + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (x) => x.NewBlockExpiryDate, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (_) => null, + voidInitiatedLedgerEntry: (x) => x.NewBlockExpiryDate, + amendmentLedgerEntry: (_) => null + ); + } + } + + public double? VoidAmount + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidAmount, + voidInitiatedLedgerEntry: (x) => x.VoidAmount, + amendmentLedgerEntry: (_) => null + ); + } + } + + public string? VoidReason + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidReason, + voidInitiatedLedgerEntry: (x) => x.VoidReason, + amendmentLedgerEntry: (_) => null + ); + } + } + + public LedgerListByExternalIDResponse(IncrementLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse(DecrementLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse( + ExpirationChangeLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse( + CreditBlockExpiryLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse(VoidLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse( + VoidInitiatedLedgerEntry value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse(AmendmentLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListByExternalIDResponse(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickIncrementLedgerEntry(out var value)) { + /// // `value` is of type `IncrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickIncrementLedgerEntry([NotNullWhen(true)] out IncrementLedgerEntry? value) + { + value = this.Value as IncrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDecrementLedgerEntry(out var value)) { + /// // `value` is of type `DecrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDecrementLedgerEntry([NotNullWhen(true)] out DecrementLedgerEntry? value) + { + value = this.Value as DecrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickExpirationChangeLedgerEntry(out var value)) { + /// // `value` is of type `ExpirationChangeLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickExpirationChangeLedgerEntry( + [NotNullWhen(true)] out ExpirationChangeLedgerEntry? value + ) + { + value = this.Value as ExpirationChangeLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCreditBlockExpiryLedgerEntry(out var value)) { + /// // `value` is of type `CreditBlockExpiryLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCreditBlockExpiryLedgerEntry( + [NotNullWhen(true)] out CreditBlockExpiryLedgerEntry? value + ) + { + value = this.Value as CreditBlockExpiryLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidLedgerEntry(out var value)) { + /// // `value` is of type `VoidLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidLedgerEntry([NotNullWhen(true)] out VoidLedgerEntry? value) + { + value = this.Value as VoidLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidInitiatedLedgerEntry(out var value)) { + /// // `value` is of type `VoidInitiatedLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidInitiatedLedgerEntry( + [NotNullWhen(true)] out VoidInitiatedLedgerEntry? value + ) + { + value = this.Value as VoidInitiatedLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmendmentLedgerEntry(out var value)) { + /// // `value` is of type `AmendmentLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmendmentLedgerEntry([NotNullWhen(true)] out AmendmentLedgerEntry? value) + { + value = this.Value as AmendmentLedgerEntry; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action incrementLedgerEntry, + System::Action decrementLedgerEntry, + System::Action expirationChangeLedgerEntry, + System::Action creditBlockExpiryLedgerEntry, + System::Action voidLedgerEntry, + System::Action voidInitiatedLedgerEntry, + System::Action amendmentLedgerEntry + ) + { + switch (this.Value) + { + case IncrementLedgerEntry value: + incrementLedgerEntry(value); + break; + case DecrementLedgerEntry value: + decrementLedgerEntry(value); + break; + case ExpirationChangeLedgerEntry value: + expirationChangeLedgerEntry(value); + break; + case CreditBlockExpiryLedgerEntry value: + creditBlockExpiryLedgerEntry(value); + break; + case VoidLedgerEntry value: + voidLedgerEntry(value); + break; + case VoidInitiatedLedgerEntry value: + voidInitiatedLedgerEntry(value); + break; + case AmendmentLedgerEntry value: + amendmentLedgerEntry(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerListByExternalIDResponse" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func incrementLedgerEntry, + System::Func decrementLedgerEntry, + System::Func expirationChangeLedgerEntry, + System::Func creditBlockExpiryLedgerEntry, + System::Func voidLedgerEntry, + System::Func voidInitiatedLedgerEntry, + System::Func amendmentLedgerEntry + ) + { + return this.Value switch + { + IncrementLedgerEntry value => incrementLedgerEntry(value), + DecrementLedgerEntry value => decrementLedgerEntry(value), + ExpirationChangeLedgerEntry value => expirationChangeLedgerEntry(value), + CreditBlockExpiryLedgerEntry value => creditBlockExpiryLedgerEntry(value), + VoidLedgerEntry value => voidLedgerEntry(value), + VoidInitiatedLedgerEntry value => voidInitiatedLedgerEntry(value), + AmendmentLedgerEntry value => amendmentLedgerEntry(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerListByExternalIDResponse" + ), + }; + } + + public static implicit operator LedgerListByExternalIDResponse(IncrementLedgerEntry value) => + new(value); + + public static implicit operator LedgerListByExternalIDResponse(DecrementLedgerEntry value) => + new(value); + + public static implicit operator LedgerListByExternalIDResponse( + ExpirationChangeLedgerEntry value + ) => new(value); + + public static implicit operator LedgerListByExternalIDResponse( + CreditBlockExpiryLedgerEntry value + ) => new(value); + + public static implicit operator LedgerListByExternalIDResponse(VoidLedgerEntry value) => + new(value); + + public static implicit operator LedgerListByExternalIDResponse( + VoidInitiatedLedgerEntry value + ) => new(value); + + public static implicit operator LedgerListByExternalIDResponse(AmendmentLedgerEntry value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerListByExternalIDResponse" + ); + } + this.Switch( + (incrementLedgerEntry) => incrementLedgerEntry.Validate(), + (decrementLedgerEntry) => decrementLedgerEntry.Validate(), + (expirationChangeLedgerEntry) => expirationChangeLedgerEntry.Validate(), + (creditBlockExpiryLedgerEntry) => creditBlockExpiryLedgerEntry.Validate(), + (voidLedgerEntry) => voidLedgerEntry.Validate(), + (voidInitiatedLedgerEntry) => voidInitiatedLedgerEntry.Validate(), + (amendmentLedgerEntry) => amendmentLedgerEntry.Validate() + ); + } + + public virtual bool Equals(LedgerListByExternalIDResponse? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerListByExternalIDResponseConverter : JsonConverter +{ + public override LedgerListByExternalIDResponse? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? entryType; + try + { + entryType = element.GetProperty("entry_type").GetString(); + } + catch + { + entryType = null; + } + + switch (entryType) + { + case "increment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "decrement": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "expiration_change": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "credit_block_expiry": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void_initiated": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amendment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new LedgerListByExternalIDResponse(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + LedgerListByExternalIDResponse value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPage.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListPage.cs new file mode 100644 index 00000000..9050c8c8 --- /dev/null +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers.Credits; + +namespace Orb.Models.Customers.Credits.Ledger; + +public sealed class LedgerListPage( + ILedgerService service, + LedgerListParams parameters, + LedgerListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponse.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponse.cs index 5ab23e58..b8b1cb99 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponse.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponse.cs @@ -1,52 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using LedgerListPageResponseProperties = Orb.Models.Customers.Credits.Ledger.LedgerListPageResponseProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LedgerListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class LedgerListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +40,35 @@ public override void Validate() public LedgerListPageResponse() { } + public LedgerListPageResponse(LedgerListPageResponse ledgerListPageResponse) + : base(ledgerListPageResponse) { } + + public LedgerListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LedgerListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + LedgerListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static LedgerListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class LedgerListPageResponseFromRaw : IFromRawJson +{ + /// + public LedgerListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => LedgerListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponseProperties/Data.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponseProperties/Data.cs deleted file mode 100644 index 81b04ba8..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponseProperties/Data.cs +++ /dev/null @@ -1,41 +0,0 @@ -using DataVariants = Orb.Models.Customers.Credits.Ledger.LedgerListPageResponseProperties.DataVariants; -using Ledger = Orb.Models.Customers.Credits.Ledger; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListPageResponseProperties; - -/// -/// The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid -/// credits within Orb. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Data -{ - internal Data() { } - - public static DataVariants::IncrementLedgerEntry Create(Ledger::IncrementLedgerEntry value) => - new(value); - - public static DataVariants::DecrementLedgerEntry Create(Ledger::DecrementLedgerEntry value) => - new(value); - - public static DataVariants::ExpirationChangeLedgerEntry Create( - Ledger::ExpirationChangeLedgerEntry value - ) => new(value); - - public static DataVariants::CreditBlockExpiryLedgerEntry Create( - Ledger::CreditBlockExpiryLedgerEntry value - ) => new(value); - - public static DataVariants::VoidLedgerEntry Create(Ledger::VoidLedgerEntry value) => new(value); - - public static DataVariants::VoidInitiatedLedgerEntry Create( - Ledger::VoidInitiatedLedgerEntry value - ) => new(value); - - public static DataVariants::AmendmentLedgerEntry Create(Ledger::AmendmentLedgerEntry value) => - new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponseProperties/DataVariants/All.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponseProperties/DataVariants/All.cs deleted file mode 100644 index a1fc987e..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListPageResponseProperties/DataVariants/All.cs +++ /dev/null @@ -1,135 +0,0 @@ -using Ledger = Orb.Models.Customers.Credits.Ledger; -using LedgerListPageResponseProperties = Orb.Models.Customers.Credits.Ledger.LedgerListPageResponseProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListPageResponseProperties.DataVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class IncrementLedgerEntry(Ledger::IncrementLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static IncrementLedgerEntry From(Ledger::IncrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class DecrementLedgerEntry(Ledger::DecrementLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static DecrementLedgerEntry From(Ledger::DecrementLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ExpirationChangeLedgerEntry(Ledger::ExpirationChangeLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static ExpirationChangeLedgerEntry From(Ledger::ExpirationChangeLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - CreditBlockExpiryLedgerEntry, - Ledger::CreditBlockExpiryLedgerEntry - >) -)] -public sealed record class CreditBlockExpiryLedgerEntry(Ledger::CreditBlockExpiryLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static CreditBlockExpiryLedgerEntry From(Ledger::CreditBlockExpiryLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidLedgerEntry(Ledger::VoidLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static VoidLedgerEntry From(Ledger::VoidLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class VoidInitiatedLedgerEntry(Ledger::VoidInitiatedLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static VoidInitiatedLedgerEntry From(Ledger::VoidInitiatedLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmendmentLedgerEntry(Ledger::AmendmentLedgerEntry Value) - : LedgerListPageResponseProperties::Data, - Orb::IVariant -{ - public static AmendmentLedgerEntry From(Ledger::AmendmentLedgerEntry value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListParams.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListParams.cs index fe2f6109..1810cda9 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListParams.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListParams.cs @@ -1,7 +1,11 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using LedgerListParamsProperties = Orb.Models.Customers.Credits.Ledger.LedgerListParamsProperties; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers.Credits.Ledger; @@ -12,133 +16,118 @@ namespace Orb.Models.Customers.Credits.Ledger; /// This [paginated endpoint](/api-reference/pagination) lists these entries, starting /// from the most recent ledger entry. /// -/// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). +/// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). /// -/// There are four major types of modifications to credit balance, detailed below. +/// There are four major types of modifications to credit balance, detailed below. /// -/// ## Increment Credits (which optionally expire on a future date) can be added -/// via the API ([Add Ledger Entry](create-ledger-entry)). The ledger entry for such -/// an action will always contain the total eligible starting and ending balance for -/// the customer at the time the entry was added to the ledger. +/// ## Increment Credits (which optionally expire on a future date) can be +/// added via the API ([Add Ledger Entry](create-ledger-entry)). The ledger entry +/// for such an action will always contain the total eligible starting and ending +/// balance for the customer at the time the entry was added to the ledger. /// -/// ## Decrement Deductions can occur as a result of an API call to create a ledger -/// entry (see [Add Ledger Entry](create-ledger-entry)), or automatically as a result -/// of incurring usage. Both ledger entries present the `decrement` entry type. +/// ## Decrement Deductions can occur as a result of an API call to create +/// a ledger entry (see [Add Ledger Entry](create-ledger-entry)), or automatically +/// as a result of incurring usage. Both ledger entries present the `decrement` entry type. /// -/// As usage for a customer is reported into Orb, credits may be deducted according +/// As usage for a customer is reported into Orb, credits may be deducted according /// to the customer's plan configuration. An automated deduction of this type will /// result in a ledger entry, also with a starting and ending balance. In order to /// provide better tracing capabilities for automatic deductions, Orb always associates /// each automatic deduction with the `event_id` at the time of ingestion, used to /// pinpoint _why_ credit deduction took place and to ensure that credits are never -/// deducted without an associated usage event. +/// deducted without an associated usage event. /// -/// By default, Orb uses an algorithm that automatically deducts from the *soonest +/// By default, Orb uses an algorithm that automatically deducts from the *soonest /// expiring credit block* first in order to ensure that all credits are utilized /// appropriately. As an example, if trial credits with an expiration date of 2 weeks -/// from now are present for a customer, they will be used before any deductions -/// take place from a non-expiring credit block. +/// from now are present for a customer, they will be used before any deductions take +/// place from a non-expiring credit block. /// -/// If there are multiple blocks with the same expiration date, Orb will deduct from -/// the block with the *lower cost basis* first (e.g. trial credits with a \$0 cost -/// basis before paid credits with a \$5.00 cost basis). +/// If there are multiple blocks with the same expiration date, Orb will deduct +/// from the block with the *lower cost basis* first (e.g. trial credits with a \$0 +/// cost basis before paid credits with a \$5.00 cost basis). /// -/// It's also possible for a single usage event's deduction to _span_ credit blocks. -/// In this case, Orb will deduct from the next block, ending at the credit block -/// which consists of unexpiring credits. Each of these deductions will lead to a -/// _separate_ ledger entry, one per credit block that is deducted from. By default, -/// the customer's total credit balance in Orb can be negative as a result of a decrement. +/// It's also possible for a single usage event's deduction to _span_ credit +/// blocks. In this case, Orb will deduct from the next block, ending at the credit +/// block which consists of unexpiring credits. Each of these deductions will lead +/// to a _separate_ ledger entry, one per credit block that is deducted from. By default, +/// the customer's total credit balance in Orb can be negative as a result of a decrement. /// -/// ## Expiration change The expiry of credits can be changed as a result of the -/// API (See [Add Ledger Entry](create-ledger-entry)). This will create a ledger -/// entry that specifies the balance as well as the initial and target expiry dates. +/// ## Expiration change The expiry of credits can be changed as a result of +/// the API (See [Add Ledger Entry](create-ledger-entry)). This will create a ledger +/// entry that specifies the balance as well as the initial and target expiry dates. /// -/// Note that for this entry type, `starting_balance` will equal `ending_balance`, -/// and the `amount` represents the balance transferred. The credit block linked -/// to the ledger entry is the source credit block from which there was an expiration change +/// Note that for this entry type, `starting_balance` will equal `ending_balance`, +/// and the `amount` represents the balance transferred. The credit block linked to +/// the ledger entry is the source credit block from which there was an expiration change. /// -/// ## Credits expiry When a set of credits expire on pre-set expiration date, the -/// customer's balance automatically reflects this change and adds an entry to the -/// ledger indicating this event. Note that credit expiry should always happen close -/// to a date boundary in the customer's timezone. +/// ## Credits expiry When a set of credits expire on pre-set expiration date, +/// the customer's balance automatically reflects this change and adds an entry to +/// the ledger indicating this event. Note that credit expiry should always happen +/// close to a date boundary in the customer's timezone. /// -/// ## Void initiated Credit blocks can be voided via the API. The `amount` on this -/// entry corresponds to the number of credits that were remaining in the block at -/// time of void. `void_reason` will be populated if the void is created with a reason. +/// ## Void initiated Credit blocks can be voided via the API. The `amount` +/// on this entry corresponds to the number of credits that were remaining in the +/// block at time of void. `void_reason` will be populated if the void is created +/// with a reason. /// -/// ## Void When a set of credits is voided, the customer's balance automatically -/// reflects this change and adds an entry to the ledger indicating this event. +/// ## Void When a set of credits is voided, the customer's balance automatically +/// reflects this change and adds an entry to the ledger indicating this event. /// -/// ## Amendment When credits are added to a customer's balance as a result of a -/// correction, this entry will be added to the ledger to indicate the adjustment -/// of credits. +/// ## Amendment When credits are added to a customer's balance as a result +/// of a correction, this entry will be added to the ledger to indicate the adjustment +/// of credits. /// -public sealed record class LedgerListParams : Orb::ParamsBase +public sealed record class LedgerListParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } - public System::DateTime? CreatedAtGt + public System::DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public System::DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public System::DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public System::DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -146,14 +135,8 @@ public sealed record class LedgerListParams : Orb::ParamsBase /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// @@ -162,45 +145,32 @@ public string? Currency /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } - public LedgerListParamsProperties::EntryStatus? EntryStatus + public ApiEnum? EntryStatus { get { - if (!this.QueryProperties.TryGetValue("entry_status", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawQueryData, + "entry_status" ); } - set - { - this.QueryProperties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawQueryData, "entry_status", value); } } - public LedgerListParamsProperties::EntryType? EntryType + public ApiEnum? EntryType { get { - if (!this.QueryProperties.TryGetValue("entry_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawQueryData, + "entry_type" ); } - set { this.QueryProperties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "entry_type", value); } } /// @@ -208,48 +178,182 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } public string? MinimumAmount { - get - { - if (!this.QueryProperties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawQueryData, "minimum_amount"); } + init { JsonModel.Set(this._rawQueryData, "minimum_amount", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); - } + public LedgerListParams() { } + + public LedgerListParams(LedgerListParams ledgerListParams) + : base(ledgerListParams) { } + + public LedgerListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LedgerListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static LedgerListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/credits/ledger", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter(typeof(EntryStatusConverter))] +public enum EntryStatus +{ + Committed, + Pending, +} + +sealed class EntryStatusConverter : JsonConverter +{ + public override EntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => EntryStatus.Committed, + "pending" => EntryStatus.Pending, + _ => (EntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EntryStatus.Committed => "committed", + EntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(EntryTypeConverter))] +public enum EntryType +{ + Increment, + Decrement, + ExpirationChange, + CreditBlockExpiry, + Void, + VoidInitiated, + Amendment, +} + +sealed class EntryTypeConverter : JsonConverter +{ + public override EntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => EntryType.Increment, + "decrement" => EntryType.Decrement, + "expiration_change" => EntryType.ExpirationChange, + "credit_block_expiry" => EntryType.CreditBlockExpiry, + "void" => EntryType.Void, + "void_initiated" => EntryType.VoidInitiated, + "amendment" => EntryType.Amendment, + _ => (EntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EntryType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EntryType.Increment => "increment", + EntryType.Decrement => "decrement", + EntryType.ExpirationChange => "expiration_change", + EntryType.CreditBlockExpiry => "credit_block_expiry", + EntryType.Void => "void", + EntryType.VoidInitiated => "void_initiated", + EntryType.Amendment => "amendment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListParamsProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListParamsProperties/EntryStatus.cs deleted file mode 100644 index 41e3b1de..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListParamsProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListParamsProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListParamsProperties/EntryType.cs deleted file mode 100644 index bef10c98..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/LedgerListParamsProperties/EntryType.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.LedgerListParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Increment = new("increment"); - - public static readonly EntryType Decrement = new("decrement"); - - public static readonly EntryType ExpirationChange = new("expiration_change"); - - public static readonly EntryType CreditBlockExpiry = new("credit_block_expiry"); - - public static readonly EntryType Void = new("void"); - - public static readonly EntryType VoidInitiated = new("void_initiated"); - - public static readonly EntryType Amendment = new("amendment"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - ExpirationChange, - CreditBlockExpiry, - Void, - VoidInitiated, - Amendment, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - "expiration_change" => Value.ExpirationChange, - "credit_block_expiry" => Value.CreditBlockExpiry, - "void" => Value.Void, - "void_initiated" => Value.VoidInitiated, - "amendment" => Value.Amendment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/LedgerListResponse.cs b/src/Orb/Models/Customers/Credits/Ledger/LedgerListResponse.cs new file mode 100644 index 00000000..c0c531ec --- /dev/null +++ b/src/Orb/Models/Customers/Credits/Ledger/LedgerListResponse.cs @@ -0,0 +1,796 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.Credits.Ledger; + +/// +/// The [Credit Ledger Entry resource](/product-catalog/prepurchase) models prepaid +/// credits within Orb. +/// +[JsonConverter(typeof(LedgerListResponseConverter))] +public record class LedgerListResponse +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + incrementLedgerEntry: (x) => x.ID, + decrementLedgerEntry: (x) => x.ID, + expirationChangeLedgerEntry: (x) => x.ID, + creditBlockExpiryLedgerEntry: (x) => x.ID, + voidLedgerEntry: (x) => x.ID, + voidInitiatedLedgerEntry: (x) => x.ID, + amendmentLedgerEntry: (x) => x.ID + ); + } + } + + public double Amount + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Amount, + decrementLedgerEntry: (x) => x.Amount, + expirationChangeLedgerEntry: (x) => x.Amount, + creditBlockExpiryLedgerEntry: (x) => x.Amount, + voidLedgerEntry: (x) => x.Amount, + voidInitiatedLedgerEntry: (x) => x.Amount, + amendmentLedgerEntry: (x) => x.Amount + ); + } + } + + public System::DateTimeOffset CreatedAt + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreatedAt, + decrementLedgerEntry: (x) => x.CreatedAt, + expirationChangeLedgerEntry: (x) => x.CreatedAt, + creditBlockExpiryLedgerEntry: (x) => x.CreatedAt, + voidLedgerEntry: (x) => x.CreatedAt, + voidInitiatedLedgerEntry: (x) => x.CreatedAt, + amendmentLedgerEntry: (x) => x.CreatedAt + ); + } + } + + public AffectedBlock CreditBlock + { + get + { + return Match( + incrementLedgerEntry: (x) => x.CreditBlock, + decrementLedgerEntry: (x) => x.CreditBlock, + expirationChangeLedgerEntry: (x) => x.CreditBlock, + creditBlockExpiryLedgerEntry: (x) => x.CreditBlock, + voidLedgerEntry: (x) => x.CreditBlock, + voidInitiatedLedgerEntry: (x) => x.CreditBlock, + amendmentLedgerEntry: (x) => x.CreditBlock + ); + } + } + + public string Currency + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Currency, + decrementLedgerEntry: (x) => x.Currency, + expirationChangeLedgerEntry: (x) => x.Currency, + creditBlockExpiryLedgerEntry: (x) => x.Currency, + voidLedgerEntry: (x) => x.Currency, + voidInitiatedLedgerEntry: (x) => x.Currency, + amendmentLedgerEntry: (x) => x.Currency + ); + } + } + + public CustomerMinified Customer + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Customer, + decrementLedgerEntry: (x) => x.Customer, + expirationChangeLedgerEntry: (x) => x.Customer, + creditBlockExpiryLedgerEntry: (x) => x.Customer, + voidLedgerEntry: (x) => x.Customer, + voidInitiatedLedgerEntry: (x) => x.Customer, + amendmentLedgerEntry: (x) => x.Customer + ); + } + } + + public string? Description + { + get + { + return Match( + incrementLedgerEntry: (x) => x.Description, + decrementLedgerEntry: (x) => x.Description, + expirationChangeLedgerEntry: (x) => x.Description, + creditBlockExpiryLedgerEntry: (x) => x.Description, + voidLedgerEntry: (x) => x.Description, + voidInitiatedLedgerEntry: (x) => x.Description, + amendmentLedgerEntry: (x) => x.Description + ); + } + } + + public double EndingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.EndingBalance, + decrementLedgerEntry: (x) => x.EndingBalance, + expirationChangeLedgerEntry: (x) => x.EndingBalance, + creditBlockExpiryLedgerEntry: (x) => x.EndingBalance, + voidLedgerEntry: (x) => x.EndingBalance, + voidInitiatedLedgerEntry: (x) => x.EndingBalance, + amendmentLedgerEntry: (x) => x.EndingBalance + ); + } + } + + public long LedgerSequenceNumber + { + get + { + return Match( + incrementLedgerEntry: (x) => x.LedgerSequenceNumber, + decrementLedgerEntry: (x) => x.LedgerSequenceNumber, + expirationChangeLedgerEntry: (x) => x.LedgerSequenceNumber, + creditBlockExpiryLedgerEntry: (x) => x.LedgerSequenceNumber, + voidLedgerEntry: (x) => x.LedgerSequenceNumber, + voidInitiatedLedgerEntry: (x) => x.LedgerSequenceNumber, + amendmentLedgerEntry: (x) => x.LedgerSequenceNumber + ); + } + } + + public double StartingBalance + { + get + { + return Match( + incrementLedgerEntry: (x) => x.StartingBalance, + decrementLedgerEntry: (x) => x.StartingBalance, + expirationChangeLedgerEntry: (x) => x.StartingBalance, + creditBlockExpiryLedgerEntry: (x) => x.StartingBalance, + voidLedgerEntry: (x) => x.StartingBalance, + voidInitiatedLedgerEntry: (x) => x.StartingBalance, + amendmentLedgerEntry: (x) => x.StartingBalance + ); + } + } + + public System::DateTimeOffset? NewBlockExpiryDate + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (x) => x.NewBlockExpiryDate, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (_) => null, + voidInitiatedLedgerEntry: (x) => x.NewBlockExpiryDate, + amendmentLedgerEntry: (_) => null + ); + } + } + + public double? VoidAmount + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidAmount, + voidInitiatedLedgerEntry: (x) => x.VoidAmount, + amendmentLedgerEntry: (_) => null + ); + } + } + + public string? VoidReason + { + get + { + return Match( + incrementLedgerEntry: (_) => null, + decrementLedgerEntry: (_) => null, + expirationChangeLedgerEntry: (_) => null, + creditBlockExpiryLedgerEntry: (_) => null, + voidLedgerEntry: (x) => x.VoidReason, + voidInitiatedLedgerEntry: (x) => x.VoidReason, + amendmentLedgerEntry: (_) => null + ); + } + } + + public LedgerListResponse(IncrementLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(DecrementLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(ExpirationChangeLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(CreditBlockExpiryLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(VoidLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(VoidInitiatedLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(AmendmentLedgerEntry value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public LedgerListResponse(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickIncrementLedgerEntry(out var value)) { + /// // `value` is of type `IncrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickIncrementLedgerEntry([NotNullWhen(true)] out IncrementLedgerEntry? value) + { + value = this.Value as IncrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDecrementLedgerEntry(out var value)) { + /// // `value` is of type `DecrementLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDecrementLedgerEntry([NotNullWhen(true)] out DecrementLedgerEntry? value) + { + value = this.Value as DecrementLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickExpirationChangeLedgerEntry(out var value)) { + /// // `value` is of type `ExpirationChangeLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickExpirationChangeLedgerEntry( + [NotNullWhen(true)] out ExpirationChangeLedgerEntry? value + ) + { + value = this.Value as ExpirationChangeLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCreditBlockExpiryLedgerEntry(out var value)) { + /// // `value` is of type `CreditBlockExpiryLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCreditBlockExpiryLedgerEntry( + [NotNullWhen(true)] out CreditBlockExpiryLedgerEntry? value + ) + { + value = this.Value as CreditBlockExpiryLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidLedgerEntry(out var value)) { + /// // `value` is of type `VoidLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidLedgerEntry([NotNullWhen(true)] out VoidLedgerEntry? value) + { + value = this.Value as VoidLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVoidInitiatedLedgerEntry(out var value)) { + /// // `value` is of type `VoidInitiatedLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVoidInitiatedLedgerEntry( + [NotNullWhen(true)] out VoidInitiatedLedgerEntry? value + ) + { + value = this.Value as VoidInitiatedLedgerEntry; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmendmentLedgerEntry(out var value)) { + /// // `value` is of type `AmendmentLedgerEntry` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmendmentLedgerEntry([NotNullWhen(true)] out AmendmentLedgerEntry? value) + { + value = this.Value as AmendmentLedgerEntry; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action incrementLedgerEntry, + System::Action decrementLedgerEntry, + System::Action expirationChangeLedgerEntry, + System::Action creditBlockExpiryLedgerEntry, + System::Action voidLedgerEntry, + System::Action voidInitiatedLedgerEntry, + System::Action amendmentLedgerEntry + ) + { + switch (this.Value) + { + case IncrementLedgerEntry value: + incrementLedgerEntry(value); + break; + case DecrementLedgerEntry value: + decrementLedgerEntry(value); + break; + case ExpirationChangeLedgerEntry value: + expirationChangeLedgerEntry(value); + break; + case CreditBlockExpiryLedgerEntry value: + creditBlockExpiryLedgerEntry(value); + break; + case VoidLedgerEntry value: + voidLedgerEntry(value); + break; + case VoidInitiatedLedgerEntry value: + voidInitiatedLedgerEntry(value); + break; + case AmendmentLedgerEntry value: + amendmentLedgerEntry(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerListResponse" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (IncrementLedgerEntry value) => {...}, + /// (DecrementLedgerEntry value) => {...}, + /// (ExpirationChangeLedgerEntry value) => {...}, + /// (CreditBlockExpiryLedgerEntry value) => {...}, + /// (VoidLedgerEntry value) => {...}, + /// (VoidInitiatedLedgerEntry value) => {...}, + /// (AmendmentLedgerEntry value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func incrementLedgerEntry, + System::Func decrementLedgerEntry, + System::Func expirationChangeLedgerEntry, + System::Func creditBlockExpiryLedgerEntry, + System::Func voidLedgerEntry, + System::Func voidInitiatedLedgerEntry, + System::Func amendmentLedgerEntry + ) + { + return this.Value switch + { + IncrementLedgerEntry value => incrementLedgerEntry(value), + DecrementLedgerEntry value => decrementLedgerEntry(value), + ExpirationChangeLedgerEntry value => expirationChangeLedgerEntry(value), + CreditBlockExpiryLedgerEntry value => creditBlockExpiryLedgerEntry(value), + VoidLedgerEntry value => voidLedgerEntry(value), + VoidInitiatedLedgerEntry value => voidInitiatedLedgerEntry(value), + AmendmentLedgerEntry value => amendmentLedgerEntry(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of LedgerListResponse" + ), + }; + } + + public static implicit operator LedgerListResponse(IncrementLedgerEntry value) => new(value); + + public static implicit operator LedgerListResponse(DecrementLedgerEntry value) => new(value); + + public static implicit operator LedgerListResponse(ExpirationChangeLedgerEntry value) => + new(value); + + public static implicit operator LedgerListResponse(CreditBlockExpiryLedgerEntry value) => + new(value); + + public static implicit operator LedgerListResponse(VoidLedgerEntry value) => new(value); + + public static implicit operator LedgerListResponse(VoidInitiatedLedgerEntry value) => + new(value); + + public static implicit operator LedgerListResponse(AmendmentLedgerEntry value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of LedgerListResponse" + ); + } + this.Switch( + (incrementLedgerEntry) => incrementLedgerEntry.Validate(), + (decrementLedgerEntry) => decrementLedgerEntry.Validate(), + (expirationChangeLedgerEntry) => expirationChangeLedgerEntry.Validate(), + (creditBlockExpiryLedgerEntry) => creditBlockExpiryLedgerEntry.Validate(), + (voidLedgerEntry) => voidLedgerEntry.Validate(), + (voidInitiatedLedgerEntry) => voidInitiatedLedgerEntry.Validate(), + (amendmentLedgerEntry) => amendmentLedgerEntry.Validate() + ); + } + + public virtual bool Equals(LedgerListResponse? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class LedgerListResponseConverter : JsonConverter +{ + public override LedgerListResponse? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? entryType; + try + { + entryType = element.GetProperty("entry_type").GetString(); + } + catch + { + entryType = null; + } + + switch (entryType) + { + case "increment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "decrement": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "expiration_change": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "credit_block_expiry": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "void_initiated": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amendment": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new LedgerListResponse(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + LedgerListResponse value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntry.cs index 444a3b9c..c320ba6e 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntry.cs @@ -1,197 +1,98 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using VoidInitiatedLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.VoidInitiatedLedgerEntryProperties; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class VoidInitiatedLedgerEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class VoidInitiatedLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required VoidInitiatedLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_status" + ); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required VoidInitiatedLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_type" + ); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -200,92 +101,46 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } - public required System::DateTime NewBlockExpiryDate + public required System::DateTimeOffset NewBlockExpiryDate { get { - if ( - !this.Properties.TryGetValue("new_block_expiry_date", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "new_block_expiry_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["new_block_expiry_date"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullStruct( + this.RawData, + "new_block_expiry_date" ); } + init { JsonModel.Set(this._rawData, "new_block_expiry_date", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } public required double VoidAmount { - get - { - if (!this.Properties.TryGetValue("void_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "void_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["void_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "void_amount"); } + init { JsonModel.Set(this._rawData, "void_amount", value); } } public required string? VoidReason { - get - { - if (!this.Properties.TryGetValue("void_reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "void_reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["void_reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "void_reason"); } + init { JsonModel.Set(this._rawData, "void_reason", value); } } + /// public override void Validate() { _ = this.ID; @@ -299,10 +154,7 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.NewBlockExpiryDate; _ = this.StartingBalance; _ = this.VoidAmount; @@ -311,18 +163,122 @@ public override void Validate() public VoidInitiatedLedgerEntry() { } + public VoidInitiatedLedgerEntry(VoidInitiatedLedgerEntry voidInitiatedLedgerEntry) + : base(voidInitiatedLedgerEntry) { } + + public VoidInitiatedLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - VoidInitiatedLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + VoidInitiatedLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static VoidInitiatedLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class VoidInitiatedLedgerEntryFromRaw : IFromRawJson +{ + /// + public VoidInitiatedLedgerEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => VoidInitiatedLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(VoidInitiatedLedgerEntryEntryStatusConverter))] +public enum VoidInitiatedLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class VoidInitiatedLedgerEntryEntryStatusConverter + : JsonConverter +{ + public override VoidInitiatedLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => VoidInitiatedLedgerEntryEntryStatus.Committed, + "pending" => VoidInitiatedLedgerEntryEntryStatus.Pending, + _ => (VoidInitiatedLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + VoidInitiatedLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + VoidInitiatedLedgerEntryEntryStatus.Committed => "committed", + VoidInitiatedLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(VoidInitiatedLedgerEntryEntryTypeConverter))] +public enum VoidInitiatedLedgerEntryEntryType +{ + VoidInitiated, +} + +sealed class VoidInitiatedLedgerEntryEntryTypeConverter + : JsonConverter +{ + public override VoidInitiatedLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "void_initiated" => VoidInitiatedLedgerEntryEntryType.VoidInitiated, + _ => (VoidInitiatedLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + VoidInitiatedLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + VoidInitiatedLedgerEntryEntryType.VoidInitiated => "void_initiated", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index dd052039..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.VoidInitiatedLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryProperties/EntryType.cs deleted file mode 100644 index 1cdd66ae..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/VoidInitiatedLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.VoidInitiatedLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType VoidInitiated = new("void_initiated"); - - readonly string _value = value; - - public enum Value - { - VoidInitiated, - } - - public Value Known() => - _value switch - { - "void_initiated" => Value.VoidInitiated, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntry.cs b/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntry.cs index bdc3a630..ac17d1f2 100644 --- a/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntry.cs +++ b/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntry.cs @@ -1,193 +1,96 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using VoidLedgerEntryProperties = Orb.Models.Customers.Credits.Ledger.VoidLedgerEntryProperties; namespace Orb.Models.Customers.Credits.Ledger; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class VoidLedgerEntry : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class VoidLedgerEntry : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required double Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required AffectedBlock CreditBlock { - get - { - if (!this.Properties.TryGetValue("credit_block", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_block", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_block"); - } - set { this.Properties["credit_block"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credit_block"); } + init { JsonModel.Set(this._rawData, "credit_block", value); } } public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Models::CustomerMinified Customer + public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } public required double EndingBalance { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } } - public required VoidLedgerEntryProperties::EntryStatus EntryStatus + public required ApiEnum EntryStatus { get { - if (!this.Properties.TryGetValue("entry_status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_status" + ); } - set { this.Properties["entry_status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_status", value); } } - public required VoidLedgerEntryProperties::EntryType EntryType + public required ApiEnum EntryType { get { - if (!this.Properties.TryGetValue("entry_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "entry_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("entry_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "entry_type" + ); } - set { this.Properties["entry_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "entry_type", value); } } public required long LedgerSequenceNumber { - get - { - if ( - !this.Properties.TryGetValue( - "ledger_sequence_number", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "ledger_sequence_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["ledger_sequence_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "ledger_sequence_number"); } + init { JsonModel.Set(this._rawData, "ledger_sequence_number", value); } } /// @@ -196,70 +99,34 @@ public required long LedgerSequenceNumber /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required double StartingBalance { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } } public required double VoidAmount { - get - { - if (!this.Properties.TryGetValue("void_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "void_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["void_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "void_amount"); } + init { JsonModel.Set(this._rawData, "void_amount", value); } } public required string? VoidReason { - get - { - if (!this.Properties.TryGetValue("void_reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "void_reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["void_reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "void_reason"); } + init { JsonModel.Set(this._rawData, "void_reason", value); } } + /// public override void Validate() { _ = this.ID; @@ -273,10 +140,7 @@ public override void Validate() this.EntryStatus.Validate(); this.EntryType.Validate(); _ = this.LedgerSequenceNumber; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.StartingBalance; _ = this.VoidAmount; _ = this.VoidReason; @@ -284,18 +148,117 @@ public override void Validate() public VoidLedgerEntry() { } + public VoidLedgerEntry(VoidLedgerEntry voidLedgerEntry) + : base(voidLedgerEntry) { } + + public VoidLedgerEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - VoidLedgerEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + VoidLedgerEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static VoidLedgerEntry FromRawUnchecked( - Generic::Dictionary properties + /// + public static VoidLedgerEntry FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class VoidLedgerEntryFromRaw : IFromRawJson +{ + /// + public VoidLedgerEntry FromRawUnchecked(IReadOnlyDictionary rawData) => + VoidLedgerEntry.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(VoidLedgerEntryEntryStatusConverter))] +public enum VoidLedgerEntryEntryStatus +{ + Committed, + Pending, +} + +sealed class VoidLedgerEntryEntryStatusConverter : JsonConverter +{ + public override VoidLedgerEntryEntryStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "committed" => VoidLedgerEntryEntryStatus.Committed, + "pending" => VoidLedgerEntryEntryStatus.Pending, + _ => (VoidLedgerEntryEntryStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + VoidLedgerEntryEntryStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + VoidLedgerEntryEntryStatus.Committed => "committed", + VoidLedgerEntryEntryStatus.Pending => "pending", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(VoidLedgerEntryEntryTypeConverter))] +public enum VoidLedgerEntryEntryType +{ + Void, +} + +sealed class VoidLedgerEntryEntryTypeConverter : JsonConverter +{ + public override VoidLedgerEntryEntryType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "void" => VoidLedgerEntryEntryType.Void, + _ => (VoidLedgerEntryEntryType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + VoidLedgerEntryEntryType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + VoidLedgerEntryEntryType.Void => "void", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntryProperties/EntryStatus.cs b/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntryProperties/EntryStatus.cs deleted file mode 100644 index 2c681c03..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntryProperties/EntryStatus.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.VoidLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryStatus(string value) : Orb::IEnum -{ - public static readonly EntryStatus Committed = new("committed"); - - public static readonly EntryStatus Pending = new("pending"); - - readonly string _value = value; - - public enum Value - { - Committed, - Pending, - } - - public Value Known() => - _value switch - { - "committed" => Value.Committed, - "pending" => Value.Pending, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryStatus FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntryProperties/EntryType.cs b/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntryProperties/EntryType.cs deleted file mode 100644 index ac7928bd..00000000 --- a/src/Orb/Models/Customers/Credits/Ledger/VoidLedgerEntryProperties/EntryType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.Ledger.VoidLedgerEntryProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class EntryType(string value) : Orb::IEnum -{ - public static readonly EntryType Void = new("void"); - - readonly string _value = value; - - public enum Value - { - Void, - } - - public Value Known() => - _value switch - { - "void" => Value.Void, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static EntryType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParams.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParams.cs index 61e38564..98a360bf 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParams.cs @@ -1,44 +1,41 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; -using TopUpCreateByExternalIDParamsProperties = Orb.Models.Customers.Credits.TopUps.TopUpCreateByExternalIDParamsProperties; namespace Orb.Models.Customers.Credits.TopUps; /// /// This endpoint allows you to create a new top-up for a specified customer's balance. -/// While this top-up is active, the customer's balance will added in increments of -/// the specified amount whenever the balance reaches the specified threshold. +/// While this top-up is active, the customer's balance will added in increments +/// of the specified amount whenever the balance reaches the specified threshold. /// -/// If a top-up already exists for this customer in the same currency, the existing -/// top-up will be replaced. +/// If a top-up already exists for this customer in the same currency, the existing +/// top-up will be replaced. /// -public sealed record class TopUpCreateByExternalIDParams : Orb::ParamsBase +public sealed record class TopUpCreateByExternalIDParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } /// /// The amount to increment when the threshold is reached. /// public required string Amount { - get - { - if (!this.BodyProperties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.BodyProperties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "amount"); } + init { JsonModel.Set(this._rawBodyData, "amount", value); } } /// @@ -47,43 +44,23 @@ public required string Amount /// public required string Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// /// Settings for invoices generated by triggered top-ups. /// - public required TopUpCreateByExternalIDParamsProperties::InvoiceSettings InvoiceSettings + public required TopUpCreateByExternalIDParamsInvoiceSettings InvoiceSettings { get { - if (!this.BodyProperties.TryGetValue("invoice_settings", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_settings", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("invoice_settings"); - } - set - { - this.BodyProperties["invoice_settings"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawBodyData, + "invoice_settings" ); } + init { JsonModel.Set(this._rawBodyData, "invoice_settings", value); } } /// @@ -91,28 +68,8 @@ public required string Currency /// public required string PerUnitCostBasis { - get - { - if ( - !this.BodyProperties.TryGetValue( - "per_unit_cost_basis", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("per_unit_cost_basis"); - } - set - { - this.BodyProperties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawBodyData, "per_unit_cost_basis", value); } } /// @@ -121,34 +78,24 @@ public required string PerUnitCostBasis /// public required string Threshold { - get - { - if (!this.BodyProperties.TryGetValue("threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("threshold"); - } - set { this.BodyProperties["threshold"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "threshold"); } + init { JsonModel.Set(this._rawBodyData, "threshold", value); } } /// /// The date from which the top-up is active. If unspecified, the top-up is active /// immediately. This should not be more than 10 days in the past. /// - public System::DateTime? ActiveFrom + public System::DateTimeOffset? ActiveFrom { get { - if (!this.BodyProperties.TryGetValue("active_from", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "active_from" + ); } - set { this.BodyProperties["active_from"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "active_from", value); } } /// @@ -157,75 +104,263 @@ public required string Threshold /// public long? ExpiresAfter { - get - { - if (!this.BodyProperties.TryGetValue("expires_after", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["expires_after"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "expires_after"); } + init { JsonModel.Set(this._rawBodyData, "expires_after", value); } } /// /// The unit of expires_after. /// - public TopUpCreateByExternalIDParamsProperties::ExpiresAfterUnit? ExpiresAfterUnit + public ApiEnum? ExpiresAfterUnit { get { - if ( - !this.BodyProperties.TryGetValue( - "expires_after_unit", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.BodyProperties["expires_after_unit"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawBodyData, "expires_after_unit"); } + init { JsonModel.Set(this._rawBodyData, "expires_after_unit", value); } + } + + public TopUpCreateByExternalIDParams() { } + + public TopUpCreateByExternalIDParams( + TopUpCreateByExternalIDParams topUpCreateByExternalIDParams + ) + : base(topUpCreateByExternalIDParams) + { + this._rawBodyData = [.. topUpCreateByExternalIDParams._rawBodyData]; } - public override System::Uri Url(Orb::IOrbClient client) + public TopUpCreateByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpCreateByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpCreateByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/credits/top_ups", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +/// +/// Settings for invoices generated by triggered top-ups. +/// +[JsonConverter( + typeof(JsonModelConverter< + TopUpCreateByExternalIDParamsInvoiceSettings, + TopUpCreateByExternalIDParamsInvoiceSettingsFromRaw + >) +)] +public sealed record class TopUpCreateByExternalIDParamsInvoiceSettings : JsonModel +{ + /// + /// Whether the credits purchase invoice should auto collect with the customer's + /// saved payment method. + /// + public required bool AutoCollection + { + get { return JsonModel.GetNotNullStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } + } + + /// + /// The net terms determines the difference between the invoice date and the + /// issue date for the invoice. If you intend the invoice to be due on issue, + /// set this to 0. + /// + public required long NetTerms + { + get { return JsonModel.GetNotNullStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } + } + + /// + /// An optional memo to display on the invoice. + /// + public string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + /// + /// When true, credit blocks created by this top-up will require that the corresponding + /// invoice is paid before they are drawn down from. If any topup block is pending + /// payment, further automatic top-ups will be paused until the invoice is paid + /// or voided. + /// + public bool? RequireSuccessfulPayment { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get + { + return JsonModel.GetNullableStruct(this.RawData, "require_successful_payment"); + } + init { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "require_successful_payment", value); } } + + /// + public override void Validate() + { + _ = this.AutoCollection; + _ = this.NetTerms; + _ = this.Memo; + _ = this.RequireSuccessfulPayment; + } + + public TopUpCreateByExternalIDParamsInvoiceSettings() { } + + public TopUpCreateByExternalIDParamsInvoiceSettings( + TopUpCreateByExternalIDParamsInvoiceSettings topUpCreateByExternalIDParamsInvoiceSettings + ) + : base(topUpCreateByExternalIDParamsInvoiceSettings) { } + + public TopUpCreateByExternalIDParamsInvoiceSettings( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpCreateByExternalIDParamsInvoiceSettings(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpCreateByExternalIDParamsInvoiceSettings FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TopUpCreateByExternalIDParamsInvoiceSettingsFromRaw + : IFromRawJson +{ + /// + public TopUpCreateByExternalIDParamsInvoiceSettings FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopUpCreateByExternalIDParamsInvoiceSettings.FromRawUnchecked(rawData); +} + +/// +/// The unit of expires_after. +/// +[JsonConverter(typeof(TopUpCreateByExternalIDParamsExpiresAfterUnitConverter))] +public enum TopUpCreateByExternalIDParamsExpiresAfterUnit +{ + Day, + Month, +} + +sealed class TopUpCreateByExternalIDParamsExpiresAfterUnitConverter + : JsonConverter +{ + public override TopUpCreateByExternalIDParamsExpiresAfterUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => TopUpCreateByExternalIDParamsExpiresAfterUnit.Day, + "month" => TopUpCreateByExternalIDParamsExpiresAfterUnit.Month, + _ => (TopUpCreateByExternalIDParamsExpiresAfterUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TopUpCreateByExternalIDParamsExpiresAfterUnit value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TopUpCreateByExternalIDParamsExpiresAfterUnit.Day => "day", + TopUpCreateByExternalIDParamsExpiresAfterUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsProperties/ExpiresAfterUnit.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsProperties/ExpiresAfterUnit.cs deleted file mode 100644 index 84e4b445..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsProperties/ExpiresAfterUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpCreateByExternalIDParamsProperties; - -/// -/// The unit of expires_after. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExpiresAfterUnit(string value) : Orb::IEnum -{ - public static readonly ExpiresAfterUnit Day = new("day"); - - public static readonly ExpiresAfterUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExpiresAfterUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsProperties/InvoiceSettings.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsProperties/InvoiceSettings.cs deleted file mode 100644 index 319ceb46..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDParamsProperties/InvoiceSettings.cs +++ /dev/null @@ -1,122 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpCreateByExternalIDParamsProperties; - -/// -/// Settings for invoices generated by triggered top-ups. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceSettings : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Whether the credits purchase invoice should auto collect with the customer's - /// saved payment method. - /// - public required bool AutoCollection - { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. - /// - public required long NetTerms - { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional memo to display on the invoice. - /// - public string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// When true, credit blocks created by this top-up will require that the corresponding - /// invoice is paid before they are drawn down from. If any topup block is pending - /// payment, further automatic top-ups will be paused until the invoice is paid - /// or voided. - /// - public bool? RequireSuccessfulPayment - { - get - { - if ( - !this.Properties.TryGetValue( - "require_successful_payment", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["require_successful_payment"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.AutoCollection; - _ = this.NetTerms; - _ = this.Memo; - _ = this.RequireSuccessfulPayment; - } - - public InvoiceSettings() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceSettings(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static InvoiceSettings FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponse.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponse.cs index f43b8e0a..607a5fe4 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponse.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponse.cs @@ -1,29 +1,26 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using TopUpCreateByExternalIDResponseProperties = Orb.Models.Customers.Credits.TopUps.TopUpCreateByExternalIDResponseProperties; namespace Orb.Models.Customers.Credits.TopUps; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TopUpCreateByExternalIDResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + TopUpCreateByExternalIDResponse, + TopUpCreateByExternalIDResponseFromRaw + >) +)] +public sealed record class TopUpCreateByExternalIDResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -31,18 +28,8 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// @@ -51,18 +38,8 @@ public required string Amount /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -72,19 +49,12 @@ public required TopUpInvoiceSettings InvoiceSettings { get { - if (!this.Properties.TryGetValue("invoice_settings", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_settings", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_settings"); - } - set - { - this.Properties["invoice_settings"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "invoice_settings" + ); } + init { JsonModel.Set(this._rawData, "invoice_settings", value); } } /// @@ -92,21 +62,8 @@ public required TopUpInvoiceSettings InvoiceSettings /// public required string PerUnitCostBasis { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("per_unit_cost_basis"); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } } /// @@ -115,18 +72,8 @@ public required string PerUnitCostBasis /// public required string Threshold { - get - { - if (!this.Properties.TryGetValue("threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("threshold"); - } - set { this.Properties["threshold"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } } /// @@ -135,36 +82,25 @@ public required string Threshold /// public long? ExpiresAfter { - get - { - if (!this.Properties.TryGetValue("expires_after", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expires_after"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "expires_after"); } + init { JsonModel.Set(this._rawData, "expires_after", value); } } /// /// The unit of expires_after. /// - public TopUpCreateByExternalIDResponseProperties::ExpiresAfterUnit? ExpiresAfterUnit + public ApiEnum? ExpiresAfterUnit { get { - if (!this.Properties.TryGetValue("expires_after_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["expires_after_unit"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "expires_after_unit"); } + init { JsonModel.Set(this._rawData, "expires_after_unit", value); } } + /// public override void Validate() { _ = this.ID; @@ -179,18 +115,85 @@ public override void Validate() public TopUpCreateByExternalIDResponse() { } + public TopUpCreateByExternalIDResponse( + TopUpCreateByExternalIDResponse topUpCreateByExternalIDResponse + ) + : base(topUpCreateByExternalIDResponse) { } + + public TopUpCreateByExternalIDResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TopUpCreateByExternalIDResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + TopUpCreateByExternalIDResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static TopUpCreateByExternalIDResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TopUpCreateByExternalIDResponseFromRaw : IFromRawJson +{ + /// + public TopUpCreateByExternalIDResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopUpCreateByExternalIDResponse.FromRawUnchecked(rawData); +} + +/// +/// The unit of expires_after. +/// +[JsonConverter(typeof(TopUpCreateByExternalIDResponseExpiresAfterUnitConverter))] +public enum TopUpCreateByExternalIDResponseExpiresAfterUnit +{ + Day, + Month, +} + +sealed class TopUpCreateByExternalIDResponseExpiresAfterUnitConverter + : JsonConverter +{ + public override TopUpCreateByExternalIDResponseExpiresAfterUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => TopUpCreateByExternalIDResponseExpiresAfterUnit.Day, + "month" => TopUpCreateByExternalIDResponseExpiresAfterUnit.Month, + _ => (TopUpCreateByExternalIDResponseExpiresAfterUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TopUpCreateByExternalIDResponseExpiresAfterUnit value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + TopUpCreateByExternalIDResponseExpiresAfterUnit.Day => "day", + TopUpCreateByExternalIDResponseExpiresAfterUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponseProperties/ExpiresAfterUnit.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponseProperties/ExpiresAfterUnit.cs deleted file mode 100644 index 95ff6c09..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateByExternalIDResponseProperties/ExpiresAfterUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpCreateByExternalIDResponseProperties; - -/// -/// The unit of expires_after. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExpiresAfterUnit(string value) : Orb::IEnum -{ - public static readonly ExpiresAfterUnit Day = new("day"); - - public static readonly ExpiresAfterUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExpiresAfterUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParams.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParams.cs index 4000697b..4bc8b35e 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParams.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParams.cs @@ -1,44 +1,41 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; -using TopUpCreateParamsProperties = Orb.Models.Customers.Credits.TopUps.TopUpCreateParamsProperties; namespace Orb.Models.Customers.Credits.TopUps; /// /// This endpoint allows you to create a new top-up for a specified customer's balance. -/// While this top-up is active, the customer's balance will added in increments of -/// the specified amount whenever the balance reaches the specified threshold. +/// While this top-up is active, the customer's balance will added in increments +/// of the specified amount whenever the balance reaches the specified threshold. /// -/// If a top-up already exists for this customer in the same currency, the existing -/// top-up will be replaced. +/// If a top-up already exists for this customer in the same currency, the existing +/// top-up will be replaced. /// -public sealed record class TopUpCreateParams : Orb::ParamsBase +public sealed record class TopUpCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string CustomerID; + public string? CustomerID { get; init; } /// /// The amount to increment when the threshold is reached. /// public required string Amount { - get - { - if (!this.BodyProperties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.BodyProperties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "amount"); } + init { JsonModel.Set(this._rawBodyData, "amount", value); } } /// @@ -47,43 +44,20 @@ public required string Amount /// public required string Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// /// Settings for invoices generated by triggered top-ups. /// - public required TopUpCreateParamsProperties::InvoiceSettings InvoiceSettings + public required InvoiceSettings InvoiceSettings { get { - if (!this.BodyProperties.TryGetValue("invoice_settings", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_settings", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("invoice_settings"); - } - set - { - this.BodyProperties["invoice_settings"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass(this.RawBodyData, "invoice_settings"); } + init { JsonModel.Set(this._rawBodyData, "invoice_settings", value); } } /// @@ -91,28 +65,8 @@ public required string Currency /// public required string PerUnitCostBasis { - get - { - if ( - !this.BodyProperties.TryGetValue( - "per_unit_cost_basis", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("per_unit_cost_basis"); - } - set - { - this.BodyProperties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawBodyData, "per_unit_cost_basis", value); } } /// @@ -121,34 +75,24 @@ public required string PerUnitCostBasis /// public required string Threshold { - get - { - if (!this.BodyProperties.TryGetValue("threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("threshold"); - } - set { this.BodyProperties["threshold"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "threshold"); } + init { JsonModel.Set(this._rawBodyData, "threshold", value); } } /// /// The date from which the top-up is active. If unspecified, the top-up is active /// immediately. This should not be more than 10 days in the past. /// - public System::DateTime? ActiveFrom + public System::DateTimeOffset? ActiveFrom { get { - if (!this.BodyProperties.TryGetValue("active_from", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "active_from" + ); } - set { this.BodyProperties["active_from"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "active_from", value); } } /// @@ -157,72 +101,245 @@ public required string Threshold /// public long? ExpiresAfter { - get - { - if (!this.BodyProperties.TryGetValue("expires_after", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["expires_after"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "expires_after"); } + init { JsonModel.Set(this._rawBodyData, "expires_after", value); } } /// /// The unit of expires_after. /// - public TopUpCreateParamsProperties::ExpiresAfterUnit? ExpiresAfterUnit + public ApiEnum? ExpiresAfterUnit { get { - if ( - !this.BodyProperties.TryGetValue( - "expires_after_unit", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.BodyProperties["expires_after_unit"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "expires_after_unit" ); } + init { JsonModel.Set(this._rawBodyData, "expires_after_unit", value); } + } + + public TopUpCreateParams() { } + + public TopUpCreateParams(TopUpCreateParams topUpCreateParams) + : base(topUpCreateParams) + { + this._rawBodyData = [.. topUpCreateParams._rawBodyData]; + } + + public TopUpCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } +#pragma warning restore CS8618 - public override System::Uri Url(Orb::IOrbClient client) + /// + public static TopUpCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/credits/top_ups", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// Settings for invoices generated by triggered top-ups. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceSettings : JsonModel +{ + /// + /// Whether the credits purchase invoice should auto collect with the customer's + /// saved payment method. + /// + public required bool AutoCollection + { + get { return JsonModel.GetNotNullStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } + } + + /// + /// The net terms determines the difference between the invoice date and the + /// issue date for the invoice. If you intend the invoice to be due on issue, + /// set this to 0. + /// + public required long NetTerms + { + get { return JsonModel.GetNotNullStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } + } + + /// + /// An optional memo to display on the invoice. + /// + public string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + /// + /// When true, credit blocks created by this top-up will require that the corresponding + /// invoice is paid before they are drawn down from. If any topup block is pending + /// payment, further automatic top-ups will be paused until the invoice is paid + /// or voided. + /// + public bool? RequireSuccessfulPayment + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "require_successful_payment"); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "require_successful_payment", value); + } + } + + /// + public override void Validate() + { + _ = this.AutoCollection; + _ = this.NetTerms; + _ = this.Memo; + _ = this.RequireSuccessfulPayment; + } + + public InvoiceSettings() { } + + public InvoiceSettings(InvoiceSettings invoiceSettings) + : base(invoiceSettings) { } + + public InvoiceSettings(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceSettings(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceSettings FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceSettingsFromRaw : IFromRawJson +{ + /// + public InvoiceSettings FromRawUnchecked(IReadOnlyDictionary rawData) => + InvoiceSettings.FromRawUnchecked(rawData); +} + +/// +/// The unit of expires_after. +/// +[JsonConverter(typeof(ExpiresAfterUnitConverter))] +public enum ExpiresAfterUnit +{ + Day, + Month, +} + +sealed class ExpiresAfterUnitConverter : JsonConverter +{ + public override ExpiresAfterUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => ExpiresAfterUnit.Day, + "month" => ExpiresAfterUnit.Month, + _ => (ExpiresAfterUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExpiresAfterUnit value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ExpiresAfterUnit.Day => "day", + ExpiresAfterUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParamsProperties/ExpiresAfterUnit.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParamsProperties/ExpiresAfterUnit.cs deleted file mode 100644 index 68057409..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParamsProperties/ExpiresAfterUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpCreateParamsProperties; - -/// -/// The unit of expires_after. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExpiresAfterUnit(string value) : Orb::IEnum -{ - public static readonly ExpiresAfterUnit Day = new("day"); - - public static readonly ExpiresAfterUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExpiresAfterUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParamsProperties/InvoiceSettings.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParamsProperties/InvoiceSettings.cs deleted file mode 100644 index b4d87859..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateParamsProperties/InvoiceSettings.cs +++ /dev/null @@ -1,122 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpCreateParamsProperties; - -/// -/// Settings for invoices generated by triggered top-ups. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceSettings : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Whether the credits purchase invoice should auto collect with the customer's - /// saved payment method. - /// - public required bool AutoCollection - { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. - /// - public required long NetTerms - { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional memo to display on the invoice. - /// - public string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// When true, credit blocks created by this top-up will require that the corresponding - /// invoice is paid before they are drawn down from. If any topup block is pending - /// payment, further automatic top-ups will be paused until the invoice is paid - /// or voided. - /// - public bool? RequireSuccessfulPayment - { - get - { - if ( - !this.Properties.TryGetValue( - "require_successful_payment", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["require_successful_payment"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.AutoCollection; - _ = this.NetTerms; - _ = this.Memo; - _ = this.RequireSuccessfulPayment; - } - - public InvoiceSettings() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceSettings(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static InvoiceSettings FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponse.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponse.cs index 87dc4c19..f72a34e7 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponse.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponse.cs @@ -1,27 +1,21 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using TopUpCreateResponseProperties = Orb.Models.Customers.Credits.TopUps.TopUpCreateResponseProperties; namespace Orb.Models.Customers.Credits.TopUps; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TopUpCreateResponse : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TopUpCreateResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -29,18 +23,8 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// @@ -49,18 +33,8 @@ public required string Amount /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -70,19 +44,12 @@ public required TopUpInvoiceSettings InvoiceSettings { get { - if (!this.Properties.TryGetValue("invoice_settings", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_settings", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_settings"); - } - set - { - this.Properties["invoice_settings"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "invoice_settings" + ); } + init { JsonModel.Set(this._rawData, "invoice_settings", value); } } /// @@ -90,21 +57,8 @@ public required TopUpInvoiceSettings InvoiceSettings /// public required string PerUnitCostBasis { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("per_unit_cost_basis"); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } } /// @@ -113,18 +67,8 @@ public required string PerUnitCostBasis /// public required string Threshold { - get - { - if (!this.Properties.TryGetValue("threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("threshold"); - } - set { this.Properties["threshold"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } } /// @@ -133,36 +77,26 @@ public required string Threshold /// public long? ExpiresAfter { - get - { - if (!this.Properties.TryGetValue("expires_after", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expires_after"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "expires_after"); } + init { JsonModel.Set(this._rawData, "expires_after", value); } } /// /// The unit of expires_after. /// - public TopUpCreateResponseProperties::ExpiresAfterUnit? ExpiresAfterUnit + public ApiEnum? ExpiresAfterUnit { get { - if (!this.Properties.TryGetValue("expires_after_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "expires_after_unit" ); } - set - { - this.Properties["expires_after_unit"] = Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "expires_after_unit", value); } } + /// public override void Validate() { _ = this.ID; @@ -177,18 +111,82 @@ public override void Validate() public TopUpCreateResponse() { } + public TopUpCreateResponse(TopUpCreateResponse topUpCreateResponse) + : base(topUpCreateResponse) { } + + public TopUpCreateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TopUpCreateResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + TopUpCreateResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static TopUpCreateResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TopUpCreateResponseFromRaw : IFromRawJson +{ + /// + public TopUpCreateResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + TopUpCreateResponse.FromRawUnchecked(rawData); +} + +/// +/// The unit of expires_after. +/// +[JsonConverter(typeof(TopUpCreateResponseExpiresAfterUnitConverter))] +public enum TopUpCreateResponseExpiresAfterUnit +{ + Day, + Month, +} + +sealed class TopUpCreateResponseExpiresAfterUnitConverter + : JsonConverter +{ + public override TopUpCreateResponseExpiresAfterUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => TopUpCreateResponseExpiresAfterUnit.Day, + "month" => TopUpCreateResponseExpiresAfterUnit.Month, + _ => (TopUpCreateResponseExpiresAfterUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TopUpCreateResponseExpiresAfterUnit value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + TopUpCreateResponseExpiresAfterUnit.Day => "day", + TopUpCreateResponseExpiresAfterUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponseProperties/ExpiresAfterUnit.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponseProperties/ExpiresAfterUnit.cs deleted file mode 100644 index 9bae42ed..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpCreateResponseProperties/ExpiresAfterUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpCreateResponseProperties; - -/// -/// The unit of expires_after. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExpiresAfterUnit(string value) : Orb::IEnum -{ - public static readonly ExpiresAfterUnit Day = new("day"); - - public static readonly ExpiresAfterUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExpiresAfterUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParams.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParams.cs index 494b787b..7442d2ee 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteByExternalIDParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; @@ -8,16 +12,56 @@ namespace Orb.Models.Customers.Credits.TopUps; /// This deactivates the top-up and voids any invoices associated with pending credit /// blocks purchased through the top-up. /// -public sealed record class TopUpDeleteByExternalIDParams : Orb::ParamsBase +public sealed record class TopUpDeleteByExternalIDParams : ParamsBase { - public required string ExternalCustomerID; + public required string ExternalCustomerID { get; init; } - public required string TopUpID; + public string? TopUpID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public TopUpDeleteByExternalIDParams() { } + + public TopUpDeleteByExternalIDParams( + TopUpDeleteByExternalIDParams topUpDeleteByExternalIDParams + ) + : base(topUpDeleteByExternalIDParams) { } + + public TopUpDeleteByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpDeleteByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpDeleteByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/credits/top_ups/{1}", this.ExternalCustomerID, @@ -25,16 +69,16 @@ public sealed record class TopUpDeleteByExternalIDParams : Orb::ParamsBase ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteParams.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteParams.cs index a082888c..7817ca68 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteParams.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpDeleteParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; @@ -8,29 +12,67 @@ namespace Orb.Models.Customers.Credits.TopUps; /// This deactivates the top-up and voids any invoices associated with pending credit /// blocks purchased through the top-up. /// -public sealed record class TopUpDeleteParams : Orb::ParamsBase +public sealed record class TopUpDeleteParams : ParamsBase { - public required string CustomerID; + public required string CustomerID { get; init; } - public required string TopUpID; + public string? TopUpID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public TopUpDeleteParams() { } + + public TopUpDeleteParams(TopUpDeleteParams topUpDeleteParams) + : base(topUpDeleteParams) { } + + public TopUpDeleteParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpDeleteParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpDeleteParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/credits/top_ups/{1}", this.CustomerID, this.TopUpID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpInvoiceSettings.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpInvoiceSettings.cs index e81b2f85..e0d3632d 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpInvoiceSettings.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpInvoiceSettings.cs @@ -1,16 +1,14 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TopUpInvoiceSettings - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TopUpInvoiceSettings : JsonModel { /// /// Whether the credits purchase invoice should auto collect with the customer's @@ -18,37 +16,19 @@ public sealed record class TopUpInvoiceSettings /// public required bool AutoCollection { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } } /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. + /// The net terms determines the difference between the invoice date and the + /// issue date for the invoice. If you intend the invoice to be due on issue, + /// set this to 0. /// public required long NetTerms { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } } /// @@ -56,14 +36,8 @@ public required long NetTerms /// public string? Memo { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } } /// @@ -76,24 +50,20 @@ public bool? RequireSuccessfulPayment { get { - if ( - !this.Properties.TryGetValue( - "require_successful_payment", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "require_successful_payment"); } - set + init { - this.Properties["require_successful_payment"] = Json::JsonSerializer.SerializeToElement( - value - ); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "require_successful_payment", value); } } + /// public override void Validate() { _ = this.AutoCollection; @@ -104,18 +74,35 @@ public override void Validate() public TopUpInvoiceSettings() { } + public TopUpInvoiceSettings(TopUpInvoiceSettings topUpInvoiceSettings) + : base(topUpInvoiceSettings) { } + + public TopUpInvoiceSettings(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TopUpInvoiceSettings(Generic::Dictionary properties) + [SetsRequiredMembers] + TopUpInvoiceSettings(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static TopUpInvoiceSettings FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class TopUpInvoiceSettingsFromRaw : IFromRawJson +{ + /// + public TopUpInvoiceSettings FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopUpInvoiceSettings.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPage.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPage.cs new file mode 100644 index 00000000..b6e2b405 --- /dev/null +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers.Credits; + +namespace Orb.Models.Customers.Credits.TopUps; + +public sealed class TopUpListByExternalIDPage( + ITopUpService service, + TopUpListByExternalIDParams parameters, + TopUpListByExternalIDPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .ListByExternalID(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponse.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponse.cs index 90d20553..4bd4de41 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponse.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponse.cs @@ -1,52 +1,45 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TopUpListByExternalIDPageResponseProperties = Orb.Models.Customers.Credits.TopUps.TopUpListByExternalIDPageResponseProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TopUpListByExternalIDPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + TopUpListByExternalIDPageResponse, + TopUpListByExternalIDPageResponseFromRaw + >) +)] +public sealed record class TopUpListByExternalIDPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +51,37 @@ public override void Validate() public TopUpListByExternalIDPageResponse() { } + public TopUpListByExternalIDPageResponse( + TopUpListByExternalIDPageResponse topUpListByExternalIDPageResponse + ) + : base(topUpListByExternalIDPageResponse) { } + + public TopUpListByExternalIDPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TopUpListByExternalIDPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + TopUpListByExternalIDPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static TopUpListByExternalIDPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class TopUpListByExternalIDPageResponseFromRaw : IFromRawJson +{ + /// + public TopUpListByExternalIDPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopUpListByExternalIDPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseProperties/Data.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseProperties/Data.cs deleted file mode 100644 index 13adcabc..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseProperties/Data.cs +++ /dev/null @@ -1,191 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Customers.Credits.TopUps.TopUpListByExternalIDPageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TopUps = Orb.Models.Customers.Credits.TopUps; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpListByExternalIDPageResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The amount to increment when the threshold is reached. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this top-up. If this is a real-world - /// currency, it must match the customer's invoicing currency. - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Settings for invoices generated by triggered top-ups. - /// - public required TopUps::TopUpInvoiceSettings InvoiceSettings - { - get - { - if (!this.Properties.TryGetValue("invoice_settings", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_settings", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_settings"); - } - set - { - this.Properties["invoice_settings"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// How much, in the customer's currency, to charge for each unit. - /// - public required string PerUnitCostBasis - { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("per_unit_cost_basis"); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The threshold at which to trigger the top-up. If the balance is at or below - /// this threshold, the top-up will be triggered. - /// - public required string Threshold - { - get - { - if (!this.Properties.TryGetValue("threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("threshold"); - } - set { this.Properties["threshold"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The number of days or months after which the top-up expires. If unspecified, - /// it does not expire. - /// - public long? ExpiresAfter - { - get - { - if (!this.Properties.TryGetValue("expires_after", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expires_after"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The unit of expires_after. - /// - public DataProperties::ExpiresAfterUnit? ExpiresAfterUnit - { - get - { - if (!this.Properties.TryGetValue("expires_after_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["expires_after_unit"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Amount; - _ = this.Currency; - this.InvoiceSettings.Validate(); - _ = this.PerUnitCostBasis; - _ = this.Threshold; - _ = this.ExpiresAfter; - this.ExpiresAfterUnit?.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseProperties/DataProperties/ExpiresAfterUnit.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseProperties/DataProperties/ExpiresAfterUnit.cs deleted file mode 100644 index d384ea7c..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDPageResponseProperties/DataProperties/ExpiresAfterUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpListByExternalIDPageResponseProperties.DataProperties; - -/// -/// The unit of expires_after. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExpiresAfterUnit(string value) : Orb::IEnum -{ - public static readonly ExpiresAfterUnit Day = new("day"); - - public static readonly ExpiresAfterUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExpiresAfterUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDParams.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDParams.cs index 47f98be1..61010456 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDParams.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDParams.cs @@ -1,16 +1,19 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; /// /// List top-ups by external ID /// -public sealed record class TopUpListByExternalIDParams : Orb::ParamsBase +public sealed record class TopUpListByExternalIDParams : ParamsBase { - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -18,14 +21,8 @@ public sealed record class TopUpListByExternalIDParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -33,36 +30,76 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public TopUpListByExternalIDParams() { } + + public TopUpListByExternalIDParams(TopUpListByExternalIDParams topUpListByExternalIDParams) + : base(topUpListByExternalIDParams) { } + + public TopUpListByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpListByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpListByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/credits/top_ups", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDResponse.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDResponse.cs new file mode 100644 index 00000000..a93986aa --- /dev/null +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListByExternalIDResponse.cs @@ -0,0 +1,196 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.Credits.TopUps; + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class TopUpListByExternalIDResponse : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The amount to increment when the threshold is reached. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The currency or custom pricing unit to use for this top-up. If this is a real-world + /// currency, it must match the customer's invoicing currency. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Settings for invoices generated by triggered top-ups. + /// + public required TopUpInvoiceSettings InvoiceSettings + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "invoice_settings" + ); + } + init { JsonModel.Set(this._rawData, "invoice_settings", value); } + } + + /// + /// How much, in the customer's currency, to charge for each unit. + /// + public required string PerUnitCostBasis + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + /// + /// The threshold at which to trigger the top-up. If the balance is at or below + /// this threshold, the top-up will be triggered. + /// + public required string Threshold + { + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } + } + + /// + /// The number of days or months after which the top-up expires. If unspecified, + /// it does not expire. + /// + public long? ExpiresAfter + { + get { return JsonModel.GetNullableStruct(this.RawData, "expires_after"); } + init { JsonModel.Set(this._rawData, "expires_after", value); } + } + + /// + /// The unit of expires_after. + /// + public ApiEnum? ExpiresAfterUnit + { + get + { + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "expires_after_unit"); + } + init { JsonModel.Set(this._rawData, "expires_after_unit", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Amount; + _ = this.Currency; + this.InvoiceSettings.Validate(); + _ = this.PerUnitCostBasis; + _ = this.Threshold; + _ = this.ExpiresAfter; + this.ExpiresAfterUnit?.Validate(); + } + + public TopUpListByExternalIDResponse() { } + + public TopUpListByExternalIDResponse( + TopUpListByExternalIDResponse topUpListByExternalIDResponse + ) + : base(topUpListByExternalIDResponse) { } + + public TopUpListByExternalIDResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpListByExternalIDResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpListByExternalIDResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TopUpListByExternalIDResponseFromRaw : IFromRawJson +{ + /// + public TopUpListByExternalIDResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopUpListByExternalIDResponse.FromRawUnchecked(rawData); +} + +/// +/// The unit of expires_after. +/// +[JsonConverter(typeof(TopUpListByExternalIDResponseExpiresAfterUnitConverter))] +public enum TopUpListByExternalIDResponseExpiresAfterUnit +{ + Day, + Month, +} + +sealed class TopUpListByExternalIDResponseExpiresAfterUnitConverter + : JsonConverter +{ + public override TopUpListByExternalIDResponseExpiresAfterUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => TopUpListByExternalIDResponseExpiresAfterUnit.Day, + "month" => TopUpListByExternalIDResponseExpiresAfterUnit.Month, + _ => (TopUpListByExternalIDResponseExpiresAfterUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TopUpListByExternalIDResponseExpiresAfterUnit value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TopUpListByExternalIDResponseExpiresAfterUnit.Day => "day", + TopUpListByExternalIDResponseExpiresAfterUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPage.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListPage.cs new file mode 100644 index 00000000..409908c2 --- /dev/null +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Customers.Credits; + +namespace Orb.Models.Customers.Credits.TopUps; + +public sealed class TopUpListPage( + ITopUpService service, + TopUpListParams parameters, + TopUpListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponse.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponse.cs index 0b09f252..7876ecd4 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponse.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponse.cs @@ -1,52 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TopUpListPageResponseProperties = Orb.Models.Customers.Credits.TopUps.TopUpListPageResponseProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TopUpListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TopUpListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +40,35 @@ public override void Validate() public TopUpListPageResponse() { } + public TopUpListPageResponse(TopUpListPageResponse topUpListPageResponse) + : base(topUpListPageResponse) { } + + public TopUpListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TopUpListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + TopUpListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static TopUpListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class TopUpListPageResponseFromRaw : IFromRawJson +{ + /// + public TopUpListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopUpListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponseProperties/Data.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponseProperties/Data.cs deleted file mode 100644 index 2009e34c..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponseProperties/Data.cs +++ /dev/null @@ -1,191 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Customers.Credits.TopUps.TopUpListPageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TopUps = Orb.Models.Customers.Credits.TopUps; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpListPageResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The amount to increment when the threshold is reached. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The currency or custom pricing unit to use for this top-up. If this is a real-world - /// currency, it must match the customer's invoicing currency. - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Settings for invoices generated by triggered top-ups. - /// - public required TopUps::TopUpInvoiceSettings InvoiceSettings - { - get - { - if (!this.Properties.TryGetValue("invoice_settings", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_settings", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_settings"); - } - set - { - this.Properties["invoice_settings"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// How much, in the customer's currency, to charge for each unit. - /// - public required string PerUnitCostBasis - { - get - { - if (!this.Properties.TryGetValue("per_unit_cost_basis", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "per_unit_cost_basis", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("per_unit_cost_basis"); - } - set - { - this.Properties["per_unit_cost_basis"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The threshold at which to trigger the top-up. If the balance is at or below - /// this threshold, the top-up will be triggered. - /// - public required string Threshold - { - get - { - if (!this.Properties.TryGetValue("threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("threshold"); - } - set { this.Properties["threshold"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The number of days or months after which the top-up expires. If unspecified, - /// it does not expire. - /// - public long? ExpiresAfter - { - get - { - if (!this.Properties.TryGetValue("expires_after", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["expires_after"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The unit of expires_after. - /// - public DataProperties::ExpiresAfterUnit? ExpiresAfterUnit - { - get - { - if (!this.Properties.TryGetValue("expires_after_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["expires_after_unit"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Amount; - _ = this.Currency; - this.InvoiceSettings.Validate(); - _ = this.PerUnitCostBasis; - _ = this.Threshold; - _ = this.ExpiresAfter; - this.ExpiresAfterUnit?.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponseProperties/DataProperties/ExpiresAfterUnit.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponseProperties/DataProperties/ExpiresAfterUnit.cs deleted file mode 100644 index e88d0a82..00000000 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListPageResponseProperties/DataProperties/ExpiresAfterUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.Credits.TopUps.TopUpListPageResponseProperties.DataProperties; - -/// -/// The unit of expires_after. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExpiresAfterUnit(string value) : Orb::IEnum -{ - public static readonly ExpiresAfterUnit Day = new("day"); - - public static readonly ExpiresAfterUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExpiresAfterUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListParams.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListParams.cs index f434b8af..b2566b19 100644 --- a/src/Orb/Models/Customers/Credits/TopUps/TopUpListParams.cs +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListParams.cs @@ -1,16 +1,19 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers.Credits.TopUps; /// /// List top-ups /// -public sealed record class TopUpListParams : Orb::ParamsBase +public sealed record class TopUpListParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -18,14 +21,8 @@ public sealed record class TopUpListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -33,33 +30,73 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public TopUpListParams() { } + + public TopUpListParams(TopUpListParams topUpListParams) + : base(topUpListParams) { } + + public TopUpListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/credits/top_ups", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/Credits/TopUps/TopUpListResponse.cs b/src/Orb/Models/Customers/Credits/TopUps/TopUpListResponse.cs new file mode 100644 index 00000000..d86c0822 --- /dev/null +++ b/src/Orb/Models/Customers/Credits/TopUps/TopUpListResponse.cs @@ -0,0 +1,192 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Customers.Credits.TopUps; + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TopUpListResponse : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The amount to increment when the threshold is reached. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The currency or custom pricing unit to use for this top-up. If this is a real-world + /// currency, it must match the customer's invoicing currency. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Settings for invoices generated by triggered top-ups. + /// + public required TopUpInvoiceSettings InvoiceSettings + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "invoice_settings" + ); + } + init { JsonModel.Set(this._rawData, "invoice_settings", value); } + } + + /// + /// How much, in the customer's currency, to charge for each unit. + /// + public required string PerUnitCostBasis + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_cost_basis"); } + init { JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } + } + + /// + /// The threshold at which to trigger the top-up. If the balance is at or below + /// this threshold, the top-up will be triggered. + /// + public required string Threshold + { + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } + } + + /// + /// The number of days or months after which the top-up expires. If unspecified, + /// it does not expire. + /// + public long? ExpiresAfter + { + get { return JsonModel.GetNullableStruct(this.RawData, "expires_after"); } + init { JsonModel.Set(this._rawData, "expires_after", value); } + } + + /// + /// The unit of expires_after. + /// + public ApiEnum? ExpiresAfterUnit + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "expires_after_unit" + ); + } + init { JsonModel.Set(this._rawData, "expires_after_unit", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Amount; + _ = this.Currency; + this.InvoiceSettings.Validate(); + _ = this.PerUnitCostBasis; + _ = this.Threshold; + _ = this.ExpiresAfter; + this.ExpiresAfterUnit?.Validate(); + } + + public TopUpListResponse() { } + + public TopUpListResponse(TopUpListResponse topUpListResponse) + : base(topUpListResponse) { } + + public TopUpListResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopUpListResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TopUpListResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TopUpListResponseFromRaw : IFromRawJson +{ + /// + public TopUpListResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + TopUpListResponse.FromRawUnchecked(rawData); +} + +/// +/// The unit of expires_after. +/// +[JsonConverter(typeof(TopUpListResponseExpiresAfterUnitConverter))] +public enum TopUpListResponseExpiresAfterUnit +{ + Day, + Month, +} + +sealed class TopUpListResponseExpiresAfterUnitConverter + : JsonConverter +{ + public override TopUpListResponseExpiresAfterUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => TopUpListResponseExpiresAfterUnit.Day, + "month" => TopUpListResponseExpiresAfterUnit.Month, + _ => (TopUpListResponseExpiresAfterUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TopUpListResponseExpiresAfterUnit value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TopUpListResponseExpiresAfterUnit.Day => "day", + TopUpListResponseExpiresAfterUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Customers/Customer.cs b/src/Orb/Models/Customers/Customer.cs index d9c71b39..af950a16 100644 --- a/src/Orb/Models/Customers/Customer.cs +++ b/src/Orb/Models/Customers/Customer.cs @@ -1,10 +1,10 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CustomerProperties = Orb.Models.Customers.CustomerProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers; @@ -12,68 +12,50 @@ namespace Orb.Models.Customers; /// /// A customer is a buyer of your products, and the other party to the billing relationship. /// -/// In Orb, customers are assigned system generated identifiers automatically, but -/// it's often desirable to have these match existing identifiers in your system. +/// In Orb, customers are assigned system generated identifiers automatically, +/// but it's often desirable to have these match existing identifiers in your system. /// To avoid having to denormalize Orb ID information, you can pass in an `external_customer_id` /// with your own identifier. See [Customer ID Aliases](/events-and-metrics/customer-aliases) -/// for further information about how these aliases work in Orb. +/// for further information about how these aliases work in Orb. /// -/// In addition to having an identifier in your system, a customer may exist in a -/// payment provider solution like Stripe. Use the `payment_provider_id` and the -/// `payment_provider` enum field to express this mapping. +/// In addition to having an identifier in your system, a customer may exist +/// in a payment provider solution like Stripe. Use the `payment_provider_id` and +/// the `payment_provider` enum field to express this mapping. /// -/// A customer also has a timezone (from the standard [IANA timezone database](https://www.iana.org/time-zones)), +/// A customer also has a timezone (from the standard [IANA timezone database](https://www.iana.org/time-zones)), /// which defaults to your account's timezone. See [Timezone localization](/essentials/timezones) -/// for information on what this timezone parameter influences within Orb. +/// for information on what this timezone parameter influences within Orb. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Customer : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Customer : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required Generic::List AdditionalEmails + public required IReadOnlyList AdditionalEmails { - get - { - if (!this.Properties.TryGetValue("additional_emails", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "additional_emails", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("additional_emails"); - } - set - { - this.Properties["additional_emails"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass>(this.RawData, "additional_emails"); } + init { JsonModel.Set(this._rawData, "additional_emails", value); } } public required bool AutoCollection { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); + get { return JsonModel.GetNotNullStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Whether invoices for this customer should be automatically issued. If true, + /// invoices will be automatically issued. If false, invoices will require manual + /// approval. If null, inherits the account-level setting. + /// + public required bool? AutoIssuance + { + get { return JsonModel.GetNullableStruct(this.RawData, "auto_issuance"); } + init { JsonModel.Set(this._rawData, "auto_issuance", value); } } /// @@ -81,63 +63,29 @@ public required bool AutoCollection /// public required string Balance { - get - { - if (!this.Properties.TryGetValue("balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("balance"); - } - set { this.Properties["balance"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "balance"); } + init { JsonModel.Set(this._rawData, "balance", value); } } - public required Models::Address? BillingAddress + public required Address? BillingAddress { - get - { - if (!this.Properties.TryGetValue("billing_address", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billing_address", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billing_address"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass
(this.RawData, "billing_address"); } + init { JsonModel.Set(this._rawData, "billing_address", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } public required string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -146,55 +94,20 @@ public required string? Currency /// public required string Email { - get - { - if (!this.Properties.TryGetValue("email", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("email", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("email"); - } - set { this.Properties["email"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "email"); } + init { JsonModel.Set(this._rawData, "email", value); } } public required bool EmailDelivery { - get - { - if (!this.Properties.TryGetValue("email_delivery", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "email_delivery", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["email_delivery"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "email_delivery"); } + init { JsonModel.Set(this._rawData, "email_delivery", value); } } public required bool? ExemptFromAutomatedTax { - get - { - if ( - !this.Properties.TryGetValue( - "exempt_from_automated_tax", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "exempt_from_automated_tax", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["exempt_from_automated_tax"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "exempt_from_automated_tax"); } + init { JsonModel.Set(this._rawData, "exempt_from_automated_tax", value); } } /// @@ -204,41 +117,17 @@ public required bool? ExemptFromAutomatedTax /// public required string? ExternalCustomerID { - get - { - if (!this.Properties.TryGetValue("external_customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_customer_id"); } + init { JsonModel.Set(this._rawData, "external_customer_id", value); } } /// /// The hierarchical relationships for this customer. /// - public required CustomerProperties::Hierarchy Hierarchy + public required Hierarchy Hierarchy { - get - { - if (!this.Properties.TryGetValue("hierarchy", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "hierarchy", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("hierarchy"); - } - set { this.Properties["hierarchy"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "hierarchy"); } + init { JsonModel.Set(this._rawData, "hierarchy", value); } } /// @@ -247,20 +136,13 @@ public required string? ExternalCustomerID /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -268,219 +150,157 @@ public required string? ExternalCustomerID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// /// This is used for creating charges or invoices in an external system via Orb. /// When not in test mode, the connection must first be configured in the Orb webapp. /// - public required CustomerProperties::PaymentProvider? PaymentProvider + public required ApiEnum? PaymentProvider { get { - if (!this.Properties.TryGetValue("payment_provider", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_provider", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_provider"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>( + this.RawData, + "payment_provider" + ); } + init { JsonModel.Set(this._rawData, "payment_provider", value); } } /// - /// The ID of this customer in an external payments solution, such as Stripe. This - /// is used for creating charges or invoices in the external system via Orb. + /// The ID of this customer in an external payments solution, such as Stripe. + /// This is used for creating charges or invoices in the external system via Orb. /// public required string? PaymentProviderID { - get - { - if (!this.Properties.TryGetValue("payment_provider_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_provider_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_provider_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "payment_provider_id"); } + init { JsonModel.Set(this._rawData, "payment_provider_id", value); } } public required string? PortalURL { - get - { - if (!this.Properties.TryGetValue("portal_url", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "portal_url", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["portal_url"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "portal_url"); } + init { JsonModel.Set(this._rawData, "portal_url", value); } } - public required Models::Address? ShippingAddress + public required Address? ShippingAddress { - get - { - if (!this.Properties.TryGetValue("shipping_address", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "shipping_address", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["shipping_address"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass
(this.RawData, "shipping_address"); } + init { JsonModel.Set(this._rawData, "shipping_address", value); } } /// - /// Tax IDs are commonly required to be displayed on customer invoices, which are - /// added to the headers of invoices. + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. /// - /// ### Supported Tax ID Countries and Types + /// ### Supported Tax ID Countries and Types /// - /// | Country | Type | Description - /// | |----------------|--------------|---------------------------------------------| - /// | Andorra | `ad_nrt` | Andorran NRT Number - /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number - /// | | Australia | `au_abn` | Australian Business Number (AU ABN) - /// | | Australia | `au_arn` | Australian Taxation Office - /// Reference Number | | Austria | `eu_vat` | European VAT Number - /// | | Bahrain | `bh_vat` | Bahraini VAT Number - /// | | Belgium | `eu_vat` | European VAT Number - /// | | Bolivia | `bo_tin` | Bolivian Tax ID - /// | | Brazil | `br_cnpj` | Brazilian CNPJ - /// Number | | Brazil | `br_cpf` | Brazilian CPF - /// Number | | Bulgaria | `bg_uic` | Bulgaria - /// Unified Identification Code | | Bulgaria | `eu_vat` | European - /// VAT Number | | Canada | `ca_bn` | Canadian - /// BN | | Canada | `ca_gst_hst` | Canadian - /// GST/HST Number | | Canada | `ca_pst_bc` | Canadian - /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian - /// PST Number (Manitoba) | | Canada | `ca_pst_sk` | Canadian - /// PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian - /// QST Number (Québec) | | Chile | `cl_tin` | Chilean - /// TIN | | China | `cn_tin` | Chinese - /// Tax ID | | Colombia | `co_nit` | Colombian - /// NIT Number | | Costa Rica | `cr_tin` | Costa - /// Rican Tax ID | | Croatia | `eu_vat` | European - /// VAT Number | | Cyprus | `eu_vat` | European - /// VAT Number | | Czech Republic | `eu_vat` | European - /// VAT Number | | Denmark | `eu_vat` | European - /// VAT Number | | Dominican Republic | `do_rcn` | Dominican - /// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian - /// RUC Number | | Egypt | `eg_tin` | Egyptian - /// Tax Identification Number | | El Salvador | `sv_nit` - /// | El Salvadorian NIT Number | | Estonia | `eu_vat` | - /// European VAT Number | | EU | `eu_oss_vat` | European One Stop Shop - /// VAT Number for non-Union scheme | | Finland | `eu_vat` | European VAT - /// Number | | France | `eu_vat` | European - /// VAT Number | | Georgia | `ge_vat` | - /// Georgian VAT | | Germany | `eu_vat` - /// | European VAT Number | | Greece - /// | `eu_vat` | European VAT Number | | - /// Hong Kong | `hk_br` | Hong Kong BR Number - /// | | Hungary | `eu_vat` | European VAT Number - /// | | Hungary | `hu_tin` | Hungary Tax Number (adószám) - /// | | Iceland | `is_vat` | Icelandic VAT - /// | | India | `in_gst` | Indian GST - /// Number | | Indonesia | `id_npwp` | Indonesian - /// NPWP Number | | Ireland | `eu_vat` | - /// European VAT Number | | Israel | `il_vat` - /// | Israel VAT | | Italy - /// | `eu_vat` | European VAT Number | | - /// Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) - /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' - /// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | - /// Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) - /// | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification - /// Number | | Kenya | `ke_pin` | Kenya Revenue Authority - /// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number - /// | | Liechtenstein | `li_uid` | Liechtensteinian - /// UID Number | | Lithuania | `eu_vat` | European VAT Number - /// | | Luxembourg | `eu_vat` | European VAT Number - /// | | Malaysia | `my_frp` | Malaysian FRP Number - /// | | Malaysia | `my_itn` | Malaysian ITN - /// | | Malaysia | `my_sst` | Malaysian SST Number | - /// | Malta | `eu_vat ` | European VAT Number | | Mexico - /// | `mx_rfc` | Mexican RFC Number | | Netherlands - /// | `eu_vat` | European VAT Number | | New Zealand | - /// `nz_gst` | New Zealand GST Number | | Nigeria | - /// `ng_tin` | Nigerian Tax Identification Number | | Norway | `no_vat` - /// | Norwegian VAT Number | | Norway | `no_voec` | Norwegian - /// VAT on e-commerce Number | | Oman | `om_vat` | Omani VAT Number - /// | | Peru | `pe_ruc` | Peruvian RUC Number - /// | | Philippines | `ph_tin ` | Philippines Tax Identification - /// Number | | Poland | `eu_vat` | European VAT Number - /// | | Portugal | `eu_vat` | European VAT Number | | - /// Romania | `eu_vat` | European VAT Number | | Romania - /// | `ro_tin` | Romanian Tax ID Number | | Russia - /// | `ru_inn` | Russian INN | | Russia | `ru_kpp` - /// | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi - /// Arabia VAT | | Serbia | `rs_pib` | Serbian PIB - /// Number | | Singapore | `sg_gst` | Singaporean GST - /// | | Singapore | `sg_uen` | Singaporean UEN - /// | | Slovakia | `eu_vat` | European VAT Number - /// | | Slovenia | `eu_vat` | European VAT Number - /// | | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) - /// | | South Africa | `za_vat` | South African VAT - /// Number | | South Korea | `kr_brn` | Korean - /// BRN | | Spain | `es_cif` - /// | Spanish NIF Number (previously Spanish CIF Number) | | Spain - /// | `eu_vat` | European VAT Number | | - /// Sweden | `eu_vat` | European VAT Number - /// | | Switzerland | `ch_vat` | Switzerland VAT Number - /// | | Taiwan | `tw_vat` | Taiwanese VAT - /// | | Thailand | `th_vat` | - /// Thai VAT | | Turkey - /// | `tr_tin` | Turkish Tax Identification Number | | Ukraine - /// | `ua_vat` | Ukrainian VAT - /// | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN - /// | | United Kingdom | `eu_vat` | Northern Ireland - /// VAT Number | | United Kingdom | `gb_vat` | United - /// Kingdom VAT Number | | United States | `us_ein` - /// | United States EIN | | Uruguay - /// | `uy_ruc` | Uruguayan RUC Number | | Venezuela - /// | `ve_rif` | Venezuelan RIF Number - /// | | Vietnam | `vn_tin` | Vietnamese Tax ID Number - /// | + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | /// - public required Models::CustomerTaxID? TaxID + public required CustomerTaxID? TaxID { - get - { - if (!this.Properties.TryGetValue("tax_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["tax_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "tax_id"); } + init { JsonModel.Set(this._rawData, "tax_id", value); } } /// @@ -490,75 +310,67 @@ public required string? PortalURL /// public required string Timezone { - get - { - if (!this.Properties.TryGetValue("timezone", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timezone", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("timezone"); - } - set { this.Properties["timezone"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "timezone"); } + init { JsonModel.Set(this._rawData, "timezone", value); } } - public CustomerProperties::AccountingSyncConfiguration? AccountingSyncConfiguration + public AccountingSyncConfiguration? AccountingSyncConfiguration { get { - if ( - !this.Properties.TryGetValue( - "accounting_sync_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "accounting_sync_configuration" ); } - set - { - this.Properties["accounting_sync_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "accounting_sync_configuration", value); } } - public CustomerProperties::ReportingConfiguration? ReportingConfiguration + /// + /// Whether automatic tax calculation is enabled for this customer. This field + /// is nullable for backwards compatibility but will always return a boolean value. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + /// Payment configuration for the customer, applicable when using Orb Invoicing + /// with a supported payment provider such as Stripe. + /// + public CustomerPaymentConfiguration? PaymentConfiguration { get { - if ( - !this.Properties.TryGetValue( - "reporting_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "payment_configuration" ); } - set + init { JsonModel.Set(this._rawData, "payment_configuration", value); } + } + + public ReportingConfiguration? ReportingConfiguration + { + get { - this.Properties["reporting_configuration"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "reporting_configuration" ); } + init { JsonModel.Set(this._rawData, "reporting_configuration", value); } } + /// public override void Validate() { _ = this.ID; - foreach (var item in this.AdditionalEmails) - { - _ = item; - } + _ = this.AdditionalEmails; _ = this.AutoCollection; + _ = this.AutoIssuance; _ = this.Balance; this.BillingAddress?.Validate(); _ = this.CreatedAt; @@ -568,10 +380,7 @@ public override void Validate() _ = this.ExemptFromAutomatedTax; _ = this.ExternalCustomerID; this.Hierarchy.Validate(); - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.Name; this.PaymentProvider?.Validate(); _ = this.PaymentProviderID; @@ -580,23 +389,616 @@ public override void Validate() this.TaxID?.Validate(); _ = this.Timezone; this.AccountingSyncConfiguration?.Validate(); + _ = this.AutomaticTaxEnabled; + this.PaymentConfiguration?.Validate(); this.ReportingConfiguration?.Validate(); } public Customer() { } + public Customer(Customer customer) + : base(customer) { } + + public Customer(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Customer(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Customer FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerFromRaw : IFromRawJson +{ + /// + public Customer FromRawUnchecked(IReadOnlyDictionary rawData) => + Customer.FromRawUnchecked(rawData); +} + +/// +/// The hierarchical relationships for this customer. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Hierarchy : JsonModel +{ + public required IReadOnlyList Children + { + get { return JsonModel.GetNotNullClass>(this.RawData, "children"); } + init { JsonModel.Set(this._rawData, "children", value); } + } + + public required CustomerMinified? Parent + { + get { return JsonModel.GetNullableClass(this.RawData, "parent"); } + init { JsonModel.Set(this._rawData, "parent", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Children) + { + item.Validate(); + } + this.Parent?.Validate(); + } + + public Hierarchy() { } + + public Hierarchy(Hierarchy hierarchy) + : base(hierarchy) { } + + public Hierarchy(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Hierarchy(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Hierarchy FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class HierarchyFromRaw : IFromRawJson +{ + /// + public Hierarchy FromRawUnchecked(IReadOnlyDictionary rawData) => + Hierarchy.FromRawUnchecked(rawData); +} + +/// +/// This is used for creating charges or invoices in an external system via Orb. +/// When not in test mode, the connection must first be configured in the Orb webapp. +/// +[JsonConverter(typeof(CustomerPaymentProviderConverter))] +public enum CustomerPaymentProvider +{ + Quickbooks, + BillCom, + StripeCharge, + StripeInvoice, + Netsuite, +} + +sealed class CustomerPaymentProviderConverter : JsonConverter +{ + public override CustomerPaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "quickbooks" => CustomerPaymentProvider.Quickbooks, + "bill.com" => CustomerPaymentProvider.BillCom, + "stripe_charge" => CustomerPaymentProvider.StripeCharge, + "stripe_invoice" => CustomerPaymentProvider.StripeInvoice, + "netsuite" => CustomerPaymentProvider.Netsuite, + _ => (CustomerPaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerPaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerPaymentProvider.Quickbooks => "quickbooks", + CustomerPaymentProvider.BillCom => "bill.com", + CustomerPaymentProvider.StripeCharge => "stripe_charge", + CustomerPaymentProvider.StripeInvoice => "stripe_invoice", + CustomerPaymentProvider.Netsuite => "netsuite", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class AccountingSyncConfiguration : JsonModel +{ + public required IReadOnlyList AccountingProviders + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "accounting_providers" + ); + } + init { JsonModel.Set(this._rawData, "accounting_providers", value); } + } + + public required bool Excluded + { + get { return JsonModel.GetNotNullStruct(this.RawData, "excluded"); } + init { JsonModel.Set(this._rawData, "excluded", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.AccountingProviders) + { + item.Validate(); + } + _ = this.Excluded; + } + + public AccountingSyncConfiguration() { } + + public AccountingSyncConfiguration(AccountingSyncConfiguration accountingSyncConfiguration) + : base(accountingSyncConfiguration) { } + + public AccountingSyncConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AccountingSyncConfiguration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AccountingSyncConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AccountingSyncConfigurationFromRaw : IFromRawJson +{ + /// + public AccountingSyncConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AccountingSyncConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AccountingProvider : JsonModel +{ + public required string? ExternalProviderID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_provider_id"); } + init { JsonModel.Set(this._rawData, "external_provider_id", value); } + } + + public required ApiEnum ProviderType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "provider_type" + ); + } + init { JsonModel.Set(this._rawData, "provider_type", value); } + } + + /// + public override void Validate() + { + _ = this.ExternalProviderID; + this.ProviderType.Validate(); + } + + public AccountingProvider() { } + + public AccountingProvider(AccountingProvider accountingProvider) + : base(accountingProvider) { } + + public AccountingProvider(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AccountingProvider(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AccountingProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AccountingProviderFromRaw : IFromRawJson +{ + /// + public AccountingProvider FromRawUnchecked(IReadOnlyDictionary rawData) => + AccountingProvider.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(AccountingProviderProviderTypeConverter))] +public enum AccountingProviderProviderType +{ + Quickbooks, + Netsuite, +} + +sealed class AccountingProviderProviderTypeConverter : JsonConverter +{ + public override AccountingProviderProviderType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "quickbooks" => AccountingProviderProviderType.Quickbooks, + "netsuite" => AccountingProviderProviderType.Netsuite, + _ => (AccountingProviderProviderType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AccountingProviderProviderType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AccountingProviderProviderType.Quickbooks => "quickbooks", + AccountingProviderProviderType.Netsuite => "netsuite", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Payment configuration for the customer, applicable when using Orb Invoicing with +/// a supported payment provider such as Stripe. +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CustomerPaymentConfiguration : JsonModel +{ + /// + /// Provider-specific payment configuration. + /// + public IReadOnlyList? PaymentProviders + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "payment_providers" + ); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "payment_providers", value); + } + } + + /// + public override void Validate() + { + foreach (var item in this.PaymentProviders ?? []) + { + item.Validate(); + } + } + + public CustomerPaymentConfiguration() { } + + public CustomerPaymentConfiguration(CustomerPaymentConfiguration customerPaymentConfiguration) + : base(customerPaymentConfiguration) { } + + public CustomerPaymentConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerPaymentConfiguration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerPaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerPaymentConfigurationFromRaw : IFromRawJson +{ + /// + public CustomerPaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerPaymentConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerPaymentConfigurationPaymentProvider, + CustomerPaymentConfigurationPaymentProviderFromRaw + >) +)] +public sealed record class CustomerPaymentConfigurationPaymentProvider : JsonModel +{ + /// + /// The payment provider to configure. + /// + public required ApiEnum< + string, + CustomerPaymentConfigurationPaymentProviderProviderType + > ProviderType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "provider_type"); + } + init { JsonModel.Set(this._rawData, "provider_type", value); } + } + + /// + /// List of Stripe payment method types to exclude for this customer. Excluded + /// payment methods will not be available for the customer to select during payment, + /// and will not be used for auto-collection. If a customer's default payment + /// method becomes excluded, Orb will attempt to use the next available compatible + /// payment method for auto-collection. + /// + public IReadOnlyList? ExcludedPaymentMethodTypes + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "excluded_payment_method_types" + ); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "excluded_payment_method_types", value); + } + } + + /// + public override void Validate() + { + this.ProviderType.Validate(); + _ = this.ExcludedPaymentMethodTypes; + } + + public CustomerPaymentConfigurationPaymentProvider() { } + + public CustomerPaymentConfigurationPaymentProvider( + CustomerPaymentConfigurationPaymentProvider customerPaymentConfigurationPaymentProvider + ) + : base(customerPaymentConfigurationPaymentProvider) { } + + public CustomerPaymentConfigurationPaymentProvider( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerPaymentConfigurationPaymentProvider(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerPaymentConfigurationPaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerPaymentConfigurationPaymentProvider( + ApiEnum providerType + ) + : this() + { + this.ProviderType = providerType; + } +} + +class CustomerPaymentConfigurationPaymentProviderFromRaw + : IFromRawJson +{ + /// + public CustomerPaymentConfigurationPaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerPaymentConfigurationPaymentProvider.FromRawUnchecked(rawData); +} + +/// +/// The payment provider to configure. +/// +[JsonConverter(typeof(CustomerPaymentConfigurationPaymentProviderProviderTypeConverter))] +public enum CustomerPaymentConfigurationPaymentProviderProviderType +{ + Stripe, +} + +sealed class CustomerPaymentConfigurationPaymentProviderProviderTypeConverter + : JsonConverter +{ + public override CustomerPaymentConfigurationPaymentProviderProviderType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => CustomerPaymentConfigurationPaymentProviderProviderType.Stripe, + _ => (CustomerPaymentConfigurationPaymentProviderProviderType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerPaymentConfigurationPaymentProviderProviderType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerPaymentConfigurationPaymentProviderProviderType.Stripe => "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ReportingConfiguration : JsonModel +{ + public required bool Exempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "exempt"); } + init { JsonModel.Set(this._rawData, "exempt", value); } + } + + /// + public override void Validate() + { + _ = this.Exempt; + } + + public ReportingConfiguration() { } + + public ReportingConfiguration(ReportingConfiguration reportingConfiguration) + : base(reportingConfiguration) { } + + public ReportingConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Customer(Generic::Dictionary properties) + [SetsRequiredMembers] + ReportingConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Customer FromRawUnchecked( - Generic::Dictionary properties + /// + public static ReportingConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public ReportingConfiguration(bool exempt) + : this() + { + this.Exempt = exempt; + } +} + +class ReportingConfigurationFromRaw : IFromRawJson +{ + /// + public ReportingConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReportingConfiguration.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Customers/CustomerCreateParams.cs b/src/Orb/Models/Customers/CustomerCreateParams.cs index 79f899fb..80548e2b 100644 --- a/src/Orb/Models/Customers/CustomerCreateParams.cs +++ b/src/Orb/Models/Customers/CustomerCreateParams.cs @@ -1,11 +1,13 @@ -using CustomerCreateParamsProperties = Orb.Models.Customers.CustomerCreateParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Customers; @@ -14,15 +16,19 @@ namespace Orb.Models.Customers; /// relationship. See [Customer](/core-concepts##customer) for an overview of the /// customer resource. /// -/// This endpoint is critical in the following Orb functionality: * Automated charges -/// can be configured by setting `payment_provider` and `payment_provider_id` to -/// automatically issue invoices * [Customer ID Aliases](/events-and-metrics/customer-aliases) +/// This endpoint is critical in the following Orb functionality: * Automated +/// charges can be configured by setting `payment_provider` and `payment_provider_id` +/// to automatically issue invoices * [Customer ID Aliases](/events-and-metrics/customer-aliases) /// can be configured by setting `external_customer_id` * [Timezone localization](/essentials/timezones) -/// can be configured on a per-customer basis by setting the `timezone` parameter +/// can be configured on a per-customer basis by setting the `timezone` parameter ///
-public sealed record class CustomerCreateParams : Orb::ParamsBase +public sealed record class CustomerCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// A valid customer email, to be used for notifications. When Orb triggers payment @@ -30,15 +36,8 @@ public sealed record class CustomerCreateParams : Orb::ParamsBase /// public required string Email { - get - { - if (!this.BodyProperties.TryGetValue("email", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("email", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("email"); - } - set { this.BodyProperties["email"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "email"); } + init { JsonModel.Set(this._rawBodyData, "email", value); } } /// @@ -46,59 +45,34 @@ public required string Email /// public required string Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } } public NewAccountingSyncConfiguration? AccountingSyncConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "accounting_sync_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["accounting_sync_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawBodyData, + "accounting_sync_configuration" + ); } + init { JsonModel.Set(this._rawBodyData, "accounting_sync_configuration", value); } } /// /// Additional email addresses for this customer. If populated, these email addresses - /// will be CC'd for customer communications. + /// will be CC'd for customer communications. The total number of email addresses + /// (including the primary email) cannot exceed 50. /// - public Generic::List? AdditionalEmails + public IReadOnlyList? AdditionalEmails { get { - if ( - !this.BodyProperties.TryGetValue("additional_emails", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.BodyProperties["additional_emails"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawBodyData, "additional_emails"); } + init { JsonModel.Set(this._rawBodyData, "additional_emails", value); } } /// @@ -108,63 +82,45 @@ public NewAccountingSyncConfiguration? AccountingSyncConfiguration /// public bool? AutoCollection { - get - { - if (!this.BodyProperties.TryGetValue("auto_collection", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_collection"); } + init { JsonModel.Set(this._rawBodyData, "auto_collection", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); - } + /// + /// Used to determine if invoices for this customer will be automatically issued. + /// If true, invoices will be automatically issued. If false, invoices will require + /// manual approval. If `null` is specified, the customer's auto issuance setting + /// will be inherited from the account-level setting. + /// + public bool? AutoIssuance + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_issuance"); } + init { JsonModel.Set(this._rawBodyData, "auto_issuance", value); } } public AddressInput? BillingAddress { get { - if (!this.BodyProperties.TryGetValue("billing_address", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["billing_address"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawBodyData, "billing_address"); } + init { JsonModel.Set(this._rawBodyData, "billing_address", value); } } /// - /// An ISO 4217 currency string used for the customer's invoices and balance. If - /// not set at creation time, will be set at subscription creation time. + /// An ISO 4217 currency string used for the customer's invoices and balance. + /// If not set at creation time, will be set at subscription creation time. /// public string? Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } public bool? EmailDelivery { - get - { - if (!this.BodyProperties.TryGetValue("email_delivery", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["email_delivery"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "email_delivery"); } + init { JsonModel.Set(this._rawBodyData, "email_delivery", value); } } /// @@ -174,24 +130,8 @@ public bool? EmailDelivery /// public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } /// @@ -201,12 +141,12 @@ public CustomerHierarchyConfig? Hierarchy { get { - if (!this.BodyProperties.TryGetValue("hierarchy", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass( + this.RawBodyData, + "hierarchy" + ); } - set { this.BodyProperties["hierarchy"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "hierarchy", value); } } /// @@ -214,290 +154,1340 @@ public CustomerHierarchyConfig? Hierarchy /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } /// - /// This is used for creating charges or invoices in an external system via Orb. - /// When not in test mode, the connection must first be configured in the Orb webapp. + /// Payment configuration for the customer, applicable when using Orb Invoicing + /// with a supported payment provider such as Stripe. /// - public CustomerCreateParamsProperties::PaymentProvider? PaymentProvider + public PaymentConfiguration? PaymentConfiguration { get { - if (!this.BodyProperties.TryGetValue("payment_provider", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawBodyData, + "payment_configuration" ); } - set + init { JsonModel.Set(this._rawBodyData, "payment_configuration", value); } + } + + /// + /// This is used for creating charges or invoices in an external system via Orb. + /// When not in test mode, the connection must first be configured in the Orb webapp. + /// + public ApiEnum? PaymentProvider + { + get { - this.BodyProperties["payment_provider"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "payment_provider" ); } + init { JsonModel.Set(this._rawBodyData, "payment_provider", value); } } /// - /// The ID of this customer in an external payments solution, such as Stripe. This - /// is used for creating charges or invoices in the external system via Orb. + /// The ID of this customer in an external payments solution, such as Stripe. + /// This is used for creating charges or invoices in the external system via Orb. /// public string? PaymentProviderID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "payment_provider_id"); } + init { JsonModel.Set(this._rawBodyData, "payment_provider_id", value); } + } + + public NewReportingConfiguration? ReportingConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "payment_provider_id", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass( + this.RawBodyData, + "reporting_configuration" + ); + } + init { JsonModel.Set(this._rawBodyData, "reporting_configuration", value); } + } - return Json::JsonSerializer.Deserialize(element); + public AddressInput? ShippingAddress + { + get + { + return JsonModel.GetNullableClass(this.RawBodyData, "shipping_address"); } - set + init { JsonModel.Set(this._rawBodyData, "shipping_address", value); } + } + + public TaxConfiguration? TaxConfiguration + { + get { - this.BodyProperties["payment_provider_id"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawBodyData, + "tax_configuration" ); } + init { JsonModel.Set(this._rawBodyData, "tax_configuration", value); } } - public NewReportingConfiguration? ReportingConfiguration + /// + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. + /// + /// ### Supported Tax ID Countries and Types + /// + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + /// + public CustomerTaxID? TaxID { - get + get { return JsonModel.GetNullableClass(this.RawBodyData, "tax_id"); } + init { JsonModel.Set(this._rawBodyData, "tax_id", value); } + } + + /// + /// A timezone identifier from the IANA timezone database, such as `"America/Los_Angeles"`. + /// This defaults to your account's timezone if not set. This cannot be changed + /// after customer creation. + /// + public string? Timezone + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "timezone"); } + init { JsonModel.Set(this._rawBodyData, "timezone", value); } + } + + public CustomerCreateParams() { } + + public CustomerCreateParams(CustomerCreateParams customerCreateParams) + : base(customerCreateParams) + { + this._rawBodyData = [.. customerCreateParams._rawBodyData]; + } + + public CustomerCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/customers") { - if ( - !this.BodyProperties.TryGetValue( - "reporting_configuration", - out Json::JsonElement element - ) - ) - return null; + Query = this.QueryString(options), + }.Uri; + } - return Json::JsonSerializer.Deserialize(element); - } - set + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - this.BodyProperties["reporting_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } +} - public AddressInput? ShippingAddress +/// +/// Payment configuration for the customer, applicable when using Orb Invoicing with +/// a supported payment provider such as Stripe. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PaymentConfiguration : JsonModel +{ + /// + /// Provider-specific payment configuration. + /// + public IReadOnlyList? PaymentProviders { get { - if (!this.BodyProperties.TryGetValue("shipping_address", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableClass>( + this.RawData, + "payment_providers" + ); + } + init + { + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawData, "payment_providers", value); } - set + } + + /// + public override void Validate() + { + foreach (var item in this.PaymentProviders ?? []) { - this.BodyProperties["shipping_address"] = Json::JsonSerializer.SerializeToElement( - value + item.Validate(); + } + } + + public PaymentConfiguration() { } + + public PaymentConfiguration(PaymentConfiguration paymentConfiguration) + : base(paymentConfiguration) { } + + public PaymentConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PaymentConfiguration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PaymentConfigurationFromRaw : IFromRawJson +{ + /// + public PaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PaymentConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PaymentProvider : JsonModel +{ + /// + /// The payment provider to configure. + /// + public required ApiEnum ProviderType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "provider_type" ); } + init { JsonModel.Set(this._rawData, "provider_type", value); } } - public CustomerCreateParamsProperties::TaxConfiguration? TaxConfiguration + /// + /// List of Stripe payment method types to exclude for this customer. Excluded + /// payment methods will not be available for the customer to select during payment, + /// and will not be used for auto-collection. If a customer's default payment + /// method becomes excluded, Orb will attempt to use the next available compatible + /// payment method for auto-collection. + /// + public IReadOnlyList? ExcludedPaymentMethodTypes { get { - if ( - !this.BodyProperties.TryGetValue("tax_configuration", out Json::JsonElement element) - ) - return null; + return JsonModel.GetNullableClass>( + this.RawData, + "excluded_payment_method_types" + ); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "excluded_payment_method_types", value); + } + } + + /// + public override void Validate() + { + this.ProviderType.Validate(); + _ = this.ExcludedPaymentMethodTypes; + } + + public PaymentProvider() { } + + public PaymentProvider(global::Orb.Models.Customers.PaymentProvider paymentProvider) + : base(paymentProvider) { } + + public PaymentProvider(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PaymentProvider(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Customers.PaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PaymentProvider(ApiEnum providerType) + : this() + { + this.ProviderType = providerType; + } +} + +class PaymentProviderFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Customers.PaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Customers.PaymentProvider.FromRawUnchecked(rawData); +} + +/// +/// The payment provider to configure. +/// +[JsonConverter(typeof(ProviderTypeConverter))] +public enum ProviderType +{ + Stripe, +} + +sealed class ProviderTypeConverter : JsonConverter +{ + public override ProviderType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => ProviderType.Stripe, + _ => (ProviderType)(-1), + }; + } - return Json::JsonSerializer.Deserialize( - element + public override void Write( + Utf8JsonWriter writer, + ProviderType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ProviderType.Stripe => "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// This is used for creating charges or invoices in an external system via Orb. +/// When not in test mode, the connection must first be configured in the Orb webapp. +/// +[JsonConverter(typeof(CustomerCreateParamsPaymentProviderConverter))] +public enum CustomerCreateParamsPaymentProvider +{ + Quickbooks, + BillCom, + StripeCharge, + StripeInvoice, + Netsuite, +} + +sealed class CustomerCreateParamsPaymentProviderConverter + : JsonConverter +{ + public override CustomerCreateParamsPaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "quickbooks" => CustomerCreateParamsPaymentProvider.Quickbooks, + "bill.com" => CustomerCreateParamsPaymentProvider.BillCom, + "stripe_charge" => CustomerCreateParamsPaymentProvider.StripeCharge, + "stripe_invoice" => CustomerCreateParamsPaymentProvider.StripeInvoice, + "netsuite" => CustomerCreateParamsPaymentProvider.Netsuite, + _ => (CustomerCreateParamsPaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerCreateParamsPaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerCreateParamsPaymentProvider.Quickbooks => "quickbooks", + CustomerCreateParamsPaymentProvider.BillCom => "bill.com", + CustomerCreateParamsPaymentProvider.StripeCharge => "stripe_charge", + CustomerCreateParamsPaymentProvider.StripeInvoice => "stripe_invoice", + CustomerCreateParamsPaymentProvider.Netsuite => "netsuite", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TaxConfigurationConverter))] +public record class TaxConfiguration +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public bool TaxExempt + { + get + { + return Match( + newAvalara: (x) => x.TaxExempt, + newTaxJar: (x) => x.TaxExempt, + newSphere: (x) => x.TaxExempt, + numeral: (x) => x.TaxExempt, + anrok: (x) => x.TaxExempt, + stripe: (x) => x.TaxExempt ); } - set + } + + public bool? AutomaticTaxEnabled + { + get { - this.BodyProperties["tax_configuration"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newAvalara: (x) => x.AutomaticTaxEnabled, + newTaxJar: (x) => x.AutomaticTaxEnabled, + newSphere: (x) => x.AutomaticTaxEnabled, + numeral: (x) => x.AutomaticTaxEnabled, + anrok: (x) => x.AutomaticTaxEnabled, + stripe: (x) => x.AutomaticTaxEnabled ); } } + public TaxConfiguration(NewAvalaraTaxConfiguration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TaxConfiguration(NewTaxJarConfiguration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TaxConfiguration(NewSphereConfiguration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TaxConfiguration(Numeral value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TaxConfiguration(Anrok value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TaxConfiguration(Stripe value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TaxConfiguration(JsonElement element) + { + this._element = element; + } + /// - /// Tax IDs are commonly required to be displayed on customer invoices, which are - /// added to the headers of invoices. + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . /// - /// ### Supported Tax ID Countries and Types + /// Consider using or if you need to handle every variant. /// - /// | Country | Type | Description - /// | |----------------|--------------|---------------------------------------------| - /// | Andorra | `ad_nrt` | Andorran NRT Number - /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number - /// | | Australia | `au_abn` | Australian Business Number (AU ABN) - /// | | Australia | `au_arn` | Australian Taxation Office - /// Reference Number | | Austria | `eu_vat` | European VAT Number - /// | | Bahrain | `bh_vat` | Bahraini VAT Number - /// | | Belgium | `eu_vat` | European VAT Number - /// | | Bolivia | `bo_tin` | Bolivian Tax ID - /// | | Brazil | `br_cnpj` | Brazilian CNPJ - /// Number | | Brazil | `br_cpf` | Brazilian CPF - /// Number | | Bulgaria | `bg_uic` | Bulgaria - /// Unified Identification Code | | Bulgaria | `eu_vat` | European - /// VAT Number | | Canada | `ca_bn` | Canadian - /// BN | | Canada | `ca_gst_hst` | Canadian - /// GST/HST Number | | Canada | `ca_pst_bc` | Canadian - /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian - /// PST Number (Manitoba) | | Canada | `ca_pst_sk` | Canadian - /// PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian - /// QST Number (Québec) | | Chile | `cl_tin` | Chilean - /// TIN | | China | `cn_tin` | Chinese - /// Tax ID | | Colombia | `co_nit` | Colombian - /// NIT Number | | Costa Rica | `cr_tin` | Costa - /// Rican Tax ID | | Croatia | `eu_vat` | European - /// VAT Number | | Cyprus | `eu_vat` | European - /// VAT Number | | Czech Republic | `eu_vat` | European - /// VAT Number | | Denmark | `eu_vat` | European - /// VAT Number | | Dominican Republic | `do_rcn` | Dominican - /// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian - /// RUC Number | | Egypt | `eg_tin` | Egyptian - /// Tax Identification Number | | El Salvador | `sv_nit` - /// | El Salvadorian NIT Number | | Estonia | `eu_vat` | - /// European VAT Number | | EU | `eu_oss_vat` | European One Stop Shop - /// VAT Number for non-Union scheme | | Finland | `eu_vat` | European VAT - /// Number | | France | `eu_vat` | European - /// VAT Number | | Georgia | `ge_vat` | - /// Georgian VAT | | Germany | `eu_vat` - /// | European VAT Number | | Greece - /// | `eu_vat` | European VAT Number | | - /// Hong Kong | `hk_br` | Hong Kong BR Number - /// | | Hungary | `eu_vat` | European VAT Number - /// | | Hungary | `hu_tin` | Hungary Tax Number (adószám) - /// | | Iceland | `is_vat` | Icelandic VAT - /// | | India | `in_gst` | Indian GST - /// Number | | Indonesia | `id_npwp` | Indonesian - /// NPWP Number | | Ireland | `eu_vat` | - /// European VAT Number | | Israel | `il_vat` - /// | Israel VAT | | Italy - /// | `eu_vat` | European VAT Number | | - /// Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) - /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' - /// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | - /// Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) - /// | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification - /// Number | | Kenya | `ke_pin` | Kenya Revenue Authority - /// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number - /// | | Liechtenstein | `li_uid` | Liechtensteinian - /// UID Number | | Lithuania | `eu_vat` | European VAT Number - /// | | Luxembourg | `eu_vat` | European VAT Number - /// | | Malaysia | `my_frp` | Malaysian FRP Number - /// | | Malaysia | `my_itn` | Malaysian ITN - /// | | Malaysia | `my_sst` | Malaysian SST Number | - /// | Malta | `eu_vat ` | European VAT Number | | Mexico - /// | `mx_rfc` | Mexican RFC Number | | Netherlands - /// | `eu_vat` | European VAT Number | | New Zealand | - /// `nz_gst` | New Zealand GST Number | | Nigeria | - /// `ng_tin` | Nigerian Tax Identification Number | | Norway | `no_vat` - /// | Norwegian VAT Number | | Norway | `no_voec` | Norwegian - /// VAT on e-commerce Number | | Oman | `om_vat` | Omani VAT Number - /// | | Peru | `pe_ruc` | Peruvian RUC Number - /// | | Philippines | `ph_tin ` | Philippines Tax Identification - /// Number | | Poland | `eu_vat` | European VAT Number - /// | | Portugal | `eu_vat` | European VAT Number | | - /// Romania | `eu_vat` | European VAT Number | | Romania - /// | `ro_tin` | Romanian Tax ID Number | | Russia - /// | `ru_inn` | Russian INN | | Russia | `ru_kpp` - /// | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi - /// Arabia VAT | | Serbia | `rs_pib` | Serbian PIB - /// Number | | Singapore | `sg_gst` | Singaporean GST - /// | | Singapore | `sg_uen` | Singaporean UEN - /// | | Slovakia | `eu_vat` | European VAT Number - /// | | Slovenia | `eu_vat` | European VAT Number - /// | | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) - /// | | South Africa | `za_vat` | South African VAT - /// Number | | South Korea | `kr_brn` | Korean - /// BRN | | Spain | `es_cif` - /// | Spanish NIF Number (previously Spanish CIF Number) | | Spain - /// | `eu_vat` | European VAT Number | | - /// Sweden | `eu_vat` | European VAT Number - /// | | Switzerland | `ch_vat` | Switzerland VAT Number - /// | | Taiwan | `tw_vat` | Taiwanese VAT - /// | | Thailand | `th_vat` | - /// Thai VAT | | Turkey - /// | `tr_tin` | Turkish Tax Identification Number | | Ukraine - /// | `ua_vat` | Ukrainian VAT - /// | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN - /// | | United Kingdom | `eu_vat` | Northern Ireland - /// VAT Number | | United Kingdom | `gb_vat` | United - /// Kingdom VAT Number | | United States | `us_ein` - /// | United States EIN | | Uruguay - /// | `uy_ruc` | Uruguayan RUC Number | | Venezuela - /// | `ve_rif` | Venezuelan RIF Number - /// | | Vietnam | `vn_tin` | Vietnamese Tax ID Number - /// | + /// + /// + /// if (instance.TryPickNewAvalara(out var value)) { + /// // `value` is of type `NewAvalaraTaxConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// /// - public Models::CustomerTaxID? TaxID + public bool TryPickNewAvalara([NotNullWhen(true)] out NewAvalaraTaxConfiguration? value) { - get - { - if (!this.BodyProperties.TryGetValue("tax_id", out Json::JsonElement element)) - return null; + value = this.Value as NewAvalaraTaxConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewTaxJar(out var value)) { + /// // `value` is of type `NewTaxJarConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewTaxJar([NotNullWhen(true)] out NewTaxJarConfiguration? value) + { + value = this.Value as NewTaxJarConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSphere(out var value)) { + /// // `value` is of type `NewSphereConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSphere([NotNullWhen(true)] out NewSphereConfiguration? value) + { + value = this.Value as NewSphereConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNumeral(out var value)) { + /// // `value` is of type `Numeral` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNumeral([NotNullWhen(true)] out Numeral? value) + { + value = this.Value as Numeral; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAnrok(out var value)) { + /// // `value` is of type `Anrok` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAnrok([NotNullWhen(true)] out Anrok? value) + { + value = this.Value as Anrok; + return value != null; + } - return Json::JsonSerializer.Deserialize(element); + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickStripe(out var value)) { + /// // `value` is of type `Stripe` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickStripe([NotNullWhen(true)] out Stripe? value) + { + value = this.Value as Stripe; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewAvalaraTaxConfiguration value) => {...}, + /// (NewTaxJarConfiguration value) => {...}, + /// (NewSphereConfiguration value) => {...}, + /// (Numeral value) => {...}, + /// (Anrok value) => {...}, + /// (Stripe value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newAvalara, + System::Action newTaxJar, + System::Action newSphere, + System::Action numeral, + System::Action anrok, + System::Action stripe + ) + { + switch (this.Value) + { + case NewAvalaraTaxConfiguration value: + newAvalara(value); + break; + case NewTaxJarConfiguration value: + newTaxJar(value); + break; + case NewSphereConfiguration value: + newSphere(value); + break; + case Numeral value: + numeral(value); + break; + case Anrok value: + anrok(value); + break; + case Stripe value: + stripe(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TaxConfiguration" + ); } - set { this.BodyProperties["tax_id"] = Json::JsonSerializer.SerializeToElement(value); } } /// - /// A timezone identifier from the IANA timezone database, such as `"America/Los_Angeles"`. - /// This defaults to your account's timezone if not set. This cannot be changed - /// after customer creation. + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewAvalaraTaxConfiguration value) => {...}, + /// (NewTaxJarConfiguration value) => {...}, + /// (NewSphereConfiguration value) => {...}, + /// (Numeral value) => {...}, + /// (Anrok value) => {...}, + /// (Stripe value) => {...} + /// ); + /// + /// /// - public string? Timezone + public T Match( + System::Func newAvalara, + System::Func newTaxJar, + System::Func newSphere, + System::Func numeral, + System::Func anrok, + System::Func stripe + ) { - get + return this.Value switch { - if (!this.BodyProperties.TryGetValue("timezone", out Json::JsonElement element)) - return null; + NewAvalaraTaxConfiguration value => newAvalara(value), + NewTaxJarConfiguration value => newTaxJar(value), + NewSphereConfiguration value => newSphere(value), + Numeral value => numeral(value), + Anrok value => anrok(value), + Stripe value => stripe(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TaxConfiguration" + ), + }; + } + + public static implicit operator TaxConfiguration(NewAvalaraTaxConfiguration value) => + new(value); + + public static implicit operator TaxConfiguration(NewTaxJarConfiguration value) => new(value); + + public static implicit operator TaxConfiguration(NewSphereConfiguration value) => new(value); + + public static implicit operator TaxConfiguration(Numeral value) => new(value); + + public static implicit operator TaxConfiguration(Anrok value) => new(value); + + public static implicit operator TaxConfiguration(Stripe value) => new(value); - return Json::JsonSerializer.Deserialize(element); + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of TaxConfiguration"); } - set { this.BodyProperties["timezone"] = Json::JsonSerializer.SerializeToElement(value); } + this.Switch( + (newAvalara) => newAvalara.Validate(), + (newTaxJar) => newTaxJar.Validate(), + (newSphere) => newSphere.Validate(), + (numeral) => numeral.Validate(), + (anrok) => anrok.Validate(), + (stripe) => stripe.Validate() + ); } - public override System::Uri Url(Orb::IOrbClient client) + public virtual bool Equals(TaxConfiguration? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TaxConfigurationConverter : JsonConverter +{ + public override TaxConfiguration? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/customers") + var element = JsonSerializer.Deserialize(ref reader, options); + string? taxProvider; + try { - Query = this.QueryString(client), - }.Uri; + taxProvider = element.GetProperty("tax_provider").GetString(); + } + catch + { + taxProvider = null; + } + + switch (taxProvider) + { + case "avalara": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "taxjar": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "sphere": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "numeral": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "anrok": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "stripe": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new TaxConfiguration(element); + } + } } - public Http::StringContent BodyContent() + public override void Write( + Utf8JsonWriter writer, + TaxConfiguration? value, + JsonSerializerOptions options + ) { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Numeral : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"numeral\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.AutomaticTaxEnabled; + } + + public Numeral() + { + this.TaxProvider = JsonSerializer.Deserialize("\"numeral\""); + } + + public Numeral(Numeral numeral) + : base(numeral) { } + + public Numeral(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"numeral\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Numeral(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Numeral FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Numeral(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; + } +} + +class NumeralFromRaw : IFromRawJson +{ + /// + public Numeral FromRawUnchecked(IReadOnlyDictionary rawData) => + Numeral.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Anrok : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"anrok\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.AutomaticTaxEnabled; + } + + public Anrok() + { + this.TaxProvider = JsonSerializer.Deserialize("\"anrok\""); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public Anrok(Anrok anrok) + : base(anrok) { } + + public Anrok(IReadOnlyDictionary rawData) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"anrok\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Anrok(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Anrok FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Anrok(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; + } +} + +class AnrokFromRaw : IFromRawJson +{ + /// + public Anrok FromRawUnchecked(IReadOnlyDictionary rawData) => + Anrok.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Stripe : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"stripe\"") + ) + ) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + throw new OrbInvalidDataException("Invalid value given for constant"); } + _ = this.AutomaticTaxEnabled; + } + + public Stripe() + { + this.TaxProvider = JsonSerializer.Deserialize("\"stripe\""); + } + + public Stripe(Stripe stripe) + : base(stripe) { } + + public Stripe(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"stripe\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Stripe(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Stripe FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Stripe(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; } } + +class StripeFromRaw : IFromRawJson +{ + /// + public Stripe FromRawUnchecked(IReadOnlyDictionary rawData) => + Stripe.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/CustomerCreateParamsProperties/PaymentProvider.cs b/src/Orb/Models/Customers/CustomerCreateParamsProperties/PaymentProvider.cs deleted file mode 100644 index 7e6e7a69..00000000 --- a/src/Orb/Models/Customers/CustomerCreateParamsProperties/PaymentProvider.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerCreateParamsProperties; - -/// -/// This is used for creating charges or invoices in an external system via Orb. When -/// not in test mode, the connection must first be configured in the Orb webapp. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PaymentProvider(string value) : Orb::IEnum -{ - public static readonly PaymentProvider Quickbooks = new("quickbooks"); - - public static readonly PaymentProvider BillCom = new("bill.com"); - - public static readonly PaymentProvider StripeCharge = new("stripe_charge"); - - public static readonly PaymentProvider StripeInvoice = new("stripe_invoice"); - - public static readonly PaymentProvider Netsuite = new("netsuite"); - - readonly string _value = value; - - public enum Value - { - Quickbooks, - BillCom, - StripeCharge, - StripeInvoice, - Netsuite, - } - - public Value Known() => - _value switch - { - "quickbooks" => Value.Quickbooks, - "bill.com" => Value.BillCom, - "stripe_charge" => Value.StripeCharge, - "stripe_invoice" => Value.StripeInvoice, - "netsuite" => Value.Netsuite, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PaymentProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/CustomerCreateParamsProperties/TaxConfiguration.cs b/src/Orb/Models/Customers/CustomerCreateParamsProperties/TaxConfiguration.cs deleted file mode 100644 index 33ced7ec..00000000 --- a/src/Orb/Models/Customers/CustomerCreateParamsProperties/TaxConfiguration.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Customers = Orb.Models.Customers; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TaxConfigurationVariants = Orb.Models.Customers.CustomerCreateParamsProperties.TaxConfigurationVariants; - -namespace Orb.Models.Customers.CustomerCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class TaxConfiguration -{ - internal TaxConfiguration() { } - - public static TaxConfigurationVariants::NewAvalaraTaxConfiguration Create( - Customers::NewAvalaraTaxConfiguration value - ) => new(value); - - public static TaxConfigurationVariants::NewTaxJarConfiguration Create( - Customers::NewTaxJarConfiguration value - ) => new(value); - - public static TaxConfigurationVariants::NewSphereConfiguration Create( - Customers::NewSphereConfiguration value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/CustomerCreateParamsProperties/TaxConfigurationVariants/All.cs b/src/Orb/Models/Customers/CustomerCreateParamsProperties/TaxConfigurationVariants/All.cs deleted file mode 100644 index ff7e8088..00000000 --- a/src/Orb/Models/Customers/CustomerCreateParamsProperties/TaxConfigurationVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using CustomerCreateParamsProperties = Orb.Models.Customers.CustomerCreateParamsProperties; -using Customers = Orb.Models.Customers; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.CustomerCreateParamsProperties.TaxConfigurationVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAvalaraTaxConfiguration(Customers::NewAvalaraTaxConfiguration Value) - : CustomerCreateParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewAvalaraTaxConfiguration From(Customers::NewAvalaraTaxConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewTaxJarConfiguration(Customers::NewTaxJarConfiguration Value) - : CustomerCreateParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewTaxJarConfiguration From(Customers::NewTaxJarConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSphereConfiguration(Customers::NewSphereConfiguration Value) - : CustomerCreateParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewSphereConfiguration From(Customers::NewSphereConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/CustomerDeleteParams.cs b/src/Orb/Models/Customers/CustomerDeleteParams.cs index 56b42569..8cef36fd 100644 --- a/src/Orb/Models/Customers/CustomerDeleteParams.cs +++ b/src/Orb/Models/Customers/CustomerDeleteParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers; @@ -10,33 +14,72 @@ namespace Orb.Models.Customers; /// invoices cannot be deleted. This operation is irreversible. Note that this is /// a _soft_ deletion, but the data will be inaccessible through the API and Orb dashboard. /// -/// For a hard-deletion, please reach out to the Orb team directly. +/// For a hard-deletion, please reach out to the Orb team directly. /// -/// **Note**: This operation happens asynchronously and can be expected to take a -/// few minutes to propagate to related resources. However, querying for the customer -/// on subsequent GET requests while deletion is in process will reflect its deletion. +/// **Note**: This operation happens asynchronously and can be expected to +/// take a few minutes to propagate to related resources. However, querying for the +/// customer on subsequent GET requests while deletion is in process will reflect +/// its deletion. /// -public sealed record class CustomerDeleteParams : Orb::ParamsBase +public sealed record class CustomerDeleteParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CustomerDeleteParams() { } + + public CustomerDeleteParams(CustomerDeleteParams customerDeleteParams) + : base(customerDeleteParams) { } + + public CustomerDeleteParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerDeleteParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerDeleteParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/CustomerFetchByExternalIDParams.cs b/src/Orb/Models/Customers/CustomerFetchByExternalIDParams.cs index db986392..5e00f67a 100644 --- a/src/Orb/Models/Customers/CustomerFetchByExternalIDParams.cs +++ b/src/Orb/Models/Customers/CustomerFetchByExternalIDParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers; @@ -8,29 +12,69 @@ namespace Orb.Models.Customers; /// This endpoint is used to fetch customer details given an `external_customer_id` /// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). /// -/// Note that the resource and semantics of this endpoint exactly mirror [Get Customer](fetch-customer). +/// Note that the resource and semantics of this endpoint exactly mirror [Get Customer](fetch-customer). /// -public sealed record class CustomerFetchByExternalIDParams : Orb::ParamsBase +public sealed record class CustomerFetchByExternalIDParams : ParamsBase { - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CustomerFetchByExternalIDParams() { } + + public CustomerFetchByExternalIDParams( + CustomerFetchByExternalIDParams customerFetchByExternalIDParams + ) + : base(customerFetchByExternalIDParams) { } + + public CustomerFetchByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerFetchByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerFetchByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/external_customer_id/{0}", this.ExternalCustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/CustomerFetchParams.cs b/src/Orb/Models/Customers/CustomerFetchParams.cs index 10c1d631..371a1e86 100644 --- a/src/Orb/Models/Customers/CustomerFetchParams.cs +++ b/src/Orb/Models/Customers/CustomerFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers; @@ -9,30 +13,68 @@ namespace Orb.Models.Customers; /// is in the process of being deleted, only the properties `id` and `deleted: true` /// will be returned. /// -/// See the [Customer resource](/core-concepts#customer) for a full discussion of -/// the Customer model. +/// See the [Customer resource](/core-concepts#customer) for a full discussion +/// of the Customer model. /// -public sealed record class CustomerFetchParams : Orb::ParamsBase +public sealed record class CustomerFetchParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CustomerFetchParams() { } + + public CustomerFetchParams(CustomerFetchParams customerFetchParams) + : base(customerFetchParams) { } + + public CustomerFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/CustomerHierarchyConfig.cs b/src/Orb/Models/Customers/CustomerHierarchyConfig.cs index a35c9011..1101abe2 100644 --- a/src/Orb/Models/Customers/CustomerHierarchyConfig.cs +++ b/src/Orb/Models/Customers/CustomerHierarchyConfig.cs @@ -1,32 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomerHierarchyConfig - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CustomerHierarchyConfig : JsonModel { /// /// A list of child customer IDs to add to the hierarchy. The desired child customers /// must not already be part of another hierarchy. /// - public Generic::List? ChildCustomerIDs + public IReadOnlyList? ChildCustomerIDs { - get + get { return JsonModel.GetNullableClass>(this.RawData, "child_customer_ids"); } + init { - if (!this.Properties.TryGetValue("child_customer_ids", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["child_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawData, "child_customer_ids", value); } } @@ -36,42 +34,48 @@ public sealed record class CustomerHierarchyConfig /// public string? ParentCustomerID { - get - { - if (!this.Properties.TryGetValue("parent_customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["parent_customer_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "parent_customer_id"); } + init { JsonModel.Set(this._rawData, "parent_customer_id", value); } } + /// public override void Validate() { - foreach (var item in this.ChildCustomerIDs ?? []) - { - _ = item; - } + _ = this.ChildCustomerIDs; _ = this.ParentCustomerID; } public CustomerHierarchyConfig() { } + public CustomerHierarchyConfig(CustomerHierarchyConfig customerHierarchyConfig) + : base(customerHierarchyConfig) { } + + public CustomerHierarchyConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomerHierarchyConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + CustomerHierarchyConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CustomerHierarchyConfig FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CustomerHierarchyConfigFromRaw : IFromRawJson +{ + /// + public CustomerHierarchyConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerHierarchyConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/CustomerListPage.cs b/src/Orb/Models/Customers/CustomerListPage.cs new file mode 100644 index 00000000..64bb39f4 --- /dev/null +++ b/src/Orb/Models/Customers/CustomerListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Customers; + +public sealed class CustomerListPage( + ICustomerService service, + CustomerListParams parameters, + CustomerListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Customers/CustomerListPageResponse.cs b/src/Orb/Models/Customers/CustomerListPageResponse.cs index 38693296..254c9273 100644 --- a/src/Orb/Models/Customers/CustomerListPageResponse.cs +++ b/src/Orb/Models/Customers/CustomerListPageResponse.cs @@ -1,50 +1,36 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomerListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CustomerListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +42,35 @@ public override void Validate() public CustomerListPageResponse() { } + public CustomerListPageResponse(CustomerListPageResponse customerListPageResponse) + : base(customerListPageResponse) { } + + public CustomerListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomerListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + CustomerListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static CustomerListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class CustomerListPageResponseFromRaw : IFromRawJson +{ + /// + public CustomerListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/CustomerListParams.cs b/src/Orb/Models/Customers/CustomerListParams.cs index 78514230..9299a895 100644 --- a/src/Orb/Models/Customers/CustomerListParams.cs +++ b/src/Orb/Models/Customers/CustomerListParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers; @@ -10,72 +13,50 @@ namespace Orb.Models.Customers; /// is ordered starting from the most recently created customer. This endpoint follows /// Orb's [standardized pagination format](/api-reference/pagination). /// -/// See [Customer](/core-concepts##customer) for an overview of the customer model. +/// See [Customer](/core-concepts##customer) for an overview of the customer model. /// -public sealed record class CustomerListParams : Orb::ParamsBase +public sealed record class CustomerListParams : ParamsBase { - public System::DateTime? CreatedAtGt + public DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[gt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[lt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -84,14 +65,8 @@ public sealed record class CustomerListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -99,30 +74,70 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public CustomerListParams() { } + + public CustomerListParams(CustomerListParams customerListParams) + : base(customerListParams) { } + + public CustomerListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/customers") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/customers") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfiguration.cs b/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfiguration.cs deleted file mode 100644 index 132438bd..00000000 --- a/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfiguration.cs +++ /dev/null @@ -1,78 +0,0 @@ -using AccountingSyncConfigurationProperties = Orb.Models.Customers.CustomerProperties.AccountingSyncConfigurationProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AccountingSyncConfiguration - : Orb::ModelBase, - Orb::IFromRaw -{ - public required Generic::List AccountingProviders - { - get - { - if (!this.Properties.TryGetValue("accounting_providers", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "accounting_providers", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("accounting_providers"); - } - set - { - this.Properties["accounting_providers"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required bool Excluded - { - get - { - if (!this.Properties.TryGetValue("excluded", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "excluded", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["excluded"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - foreach (var item in this.AccountingProviders) - { - item.Validate(); - } - _ = this.Excluded; - } - - public AccountingSyncConfiguration() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AccountingSyncConfiguration(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AccountingSyncConfiguration FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfigurationProperties/AccountingProvider.cs b/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfigurationProperties/AccountingProvider.cs deleted file mode 100644 index 8b0906fc..00000000 --- a/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfigurationProperties/AccountingProvider.cs +++ /dev/null @@ -1,73 +0,0 @@ -using AccountingProviderProperties = Orb.Models.Customers.CustomerProperties.AccountingSyncConfigurationProperties.AccountingProviderProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerProperties.AccountingSyncConfigurationProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AccountingProvider : Orb::ModelBase, Orb::IFromRaw -{ - public required string? ExternalProviderID - { - get - { - if (!this.Properties.TryGetValue("external_provider_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_provider_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_provider_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required AccountingProviderProperties::ProviderType ProviderType - { - get - { - if (!this.Properties.TryGetValue("provider_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "provider_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("provider_type"); - } - set { this.Properties["provider_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ExternalProviderID; - this.ProviderType.Validate(); - } - - public AccountingProvider() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AccountingProvider(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AccountingProvider FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfigurationProperties/AccountingProviderProperties/ProviderType.cs b/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfigurationProperties/AccountingProviderProperties/ProviderType.cs deleted file mode 100644 index ada5c6c0..00000000 --- a/src/Orb/Models/Customers/CustomerProperties/AccountingSyncConfigurationProperties/AccountingProviderProperties/ProviderType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerProperties.AccountingSyncConfigurationProperties.AccountingProviderProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ProviderType(string value) : Orb::IEnum -{ - public static readonly ProviderType Quickbooks = new("quickbooks"); - - public static readonly ProviderType Netsuite = new("netsuite"); - - readonly string _value = value; - - public enum Value - { - Quickbooks, - Netsuite, - } - - public Value Known() => - _value switch - { - "quickbooks" => Value.Quickbooks, - "netsuite" => Value.Netsuite, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ProviderType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/CustomerProperties/Hierarchy.cs b/src/Orb/Models/Customers/CustomerProperties/Hierarchy.cs deleted file mode 100644 index e148765b..00000000 --- a/src/Orb/Models/Customers/CustomerProperties/Hierarchy.cs +++ /dev/null @@ -1,74 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerProperties; - -/// -/// The hierarchical relationships for this customer. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Hierarchy : Orb::ModelBase, Orb::IFromRaw -{ - public required Generic::List Children - { - get - { - if (!this.Properties.TryGetValue("children", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "children", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("children"); - } - set { this.Properties["children"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::CustomerMinified? Parent - { - get - { - if (!this.Properties.TryGetValue("parent", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "parent", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["parent"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - foreach (var item in this.Children) - { - item.Validate(); - } - this.Parent?.Validate(); - } - - public Hierarchy() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Hierarchy(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Hierarchy FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/CustomerProperties/PaymentProvider.cs b/src/Orb/Models/Customers/CustomerProperties/PaymentProvider.cs deleted file mode 100644 index 77d0811a..00000000 --- a/src/Orb/Models/Customers/CustomerProperties/PaymentProvider.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerProperties; - -/// -/// This is used for creating charges or invoices in an external system via Orb. When -/// not in test mode, the connection must first be configured in the Orb webapp. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PaymentProvider(string value) : Orb::IEnum -{ - public static readonly PaymentProvider Quickbooks = new("quickbooks"); - - public static readonly PaymentProvider BillCom = new("bill.com"); - - public static readonly PaymentProvider StripeCharge = new("stripe_charge"); - - public static readonly PaymentProvider StripeInvoice = new("stripe_invoice"); - - public static readonly PaymentProvider Netsuite = new("netsuite"); - - readonly string _value = value; - - public enum Value - { - Quickbooks, - BillCom, - StripeCharge, - StripeInvoice, - Netsuite, - } - - public Value Known() => - _value switch - { - "quickbooks" => Value.Quickbooks, - "bill.com" => Value.BillCom, - "stripe_charge" => Value.StripeCharge, - "stripe_invoice" => Value.StripeInvoice, - "netsuite" => Value.Netsuite, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PaymentProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/CustomerProperties/ReportingConfiguration.cs b/src/Orb/Models/Customers/CustomerProperties/ReportingConfiguration.cs deleted file mode 100644 index 2ec67714..00000000 --- a/src/Orb/Models/Customers/CustomerProperties/ReportingConfiguration.cs +++ /dev/null @@ -1,51 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReportingConfiguration - : Orb::ModelBase, - Orb::IFromRaw -{ - public required bool Exempt - { - get - { - if (!this.Properties.TryGetValue("exempt", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "exempt", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["exempt"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Exempt; - } - - public ReportingConfiguration() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReportingConfiguration(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReportingConfiguration FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams.cs b/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams.cs index d27f8568..879dd0b8 100644 --- a/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams.cs +++ b/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams.cs @@ -1,42 +1,86 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers; /// /// Sync Orb's payment methods for the customer with their gateway. /// -/// This method can be called before taking an action that may cause the customer -/// to be charged, ensuring that the most up-to-date payment method is charged. +/// This method can be called before taking an action that may cause the customer +/// to be charged, ensuring that the most up-to-date payment method is charged. /// -/// **Note**: This functionality is currently only available for Stripe. +/// **Note**: This functionality is currently only available for Stripe. /// public sealed record class CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams - : Orb::ParamsBase + : ParamsBase { - public required string ExternalCustomerID; + public string? ExternalCustomerID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams() { } + + public CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams( + CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams customerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams + ) + : base(customerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams) { } + + public CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/customers/external_customer_id/{0}/sync_payment_methods_from_gateway", this.ExternalCustomerID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParams.cs b/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParams.cs index 030990f0..bac6fe4a 100644 --- a/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParams.cs +++ b/src/Orb/Models/Customers/CustomerSyncPaymentMethodsFromGatewayParams.cs @@ -1,38 +1,82 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Customers; /// /// Sync Orb's payment methods for the customer with their gateway. /// -/// This method can be called before taking an action that may cause the customer -/// to be charged, ensuring that the most up-to-date payment method is charged. +/// This method can be called before taking an action that may cause the customer +/// to be charged, ensuring that the most up-to-date payment method is charged. /// -/// **Note**: This functionality is currently only available for Stripe. +/// **Note**: This functionality is currently only available for Stripe. /// -public sealed record class CustomerSyncPaymentMethodsFromGatewayParams : Orb::ParamsBase +public sealed record class CustomerSyncPaymentMethodsFromGatewayParams : ParamsBase { - public required string CustomerID; + public string? CustomerID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public CustomerSyncPaymentMethodsFromGatewayParams() { } + + public CustomerSyncPaymentMethodsFromGatewayParams( + CustomerSyncPaymentMethodsFromGatewayParams customerSyncPaymentMethodsFromGatewayParams + ) + : base(customerSyncPaymentMethodsFromGatewayParams) { } + + public CustomerSyncPaymentMethodsFromGatewayParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerSyncPaymentMethodsFromGatewayParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerSyncPaymentMethodsFromGatewayParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/customers/{0}/sync_payment_methods_from_gateway", this.CustomerID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParams.cs b/src/Orb/Models/Customers/CustomerUpdateByExternalIDParams.cs index ab7c4766..64b7c3f9 100644 --- a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParams.cs +++ b/src/Orb/Models/Customers/CustomerUpdateByExternalIDParams.cs @@ -1,67 +1,55 @@ -using CustomerUpdateByExternalIDParamsProperties = Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Customers; /// /// This endpoint is used to update customer details given an `external_customer_id` -/// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that -/// the resource and semantics of this endpoint exactly mirror [Update Customer](update-customer). +/// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that the +/// resource and semantics of this endpoint exactly mirror [Update Customer](update-customer). /// -public sealed record class CustomerUpdateByExternalIDParams : Orb::ParamsBase +public sealed record class CustomerUpdateByExternalIDParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ID; + public string? ID { get; init; } public NewAccountingSyncConfiguration? AccountingSyncConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "accounting_sync_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["accounting_sync_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawBodyData, + "accounting_sync_configuration" + ); } + init { JsonModel.Set(this._rawBodyData, "accounting_sync_configuration", value); } } /// /// Additional email addresses for this customer. If populated, these email addresses - /// will be CC'd for customer communications. + /// will be CC'd for customer communications. The total number of email addresses + /// (including the primary email) cannot exceed 50. /// - public Generic::List? AdditionalEmails + public IReadOnlyList? AdditionalEmails { get { - if ( - !this.BodyProperties.TryGetValue("additional_emails", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.BodyProperties["additional_emails"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawBodyData, "additional_emails"); } + init { JsonModel.Set(this._rawBodyData, "additional_emails", value); } } /// @@ -71,48 +59,39 @@ public NewAccountingSyncConfiguration? AccountingSyncConfiguration /// public bool? AutoCollection { - get - { - if (!this.BodyProperties.TryGetValue("auto_collection", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_collection"); } + init { JsonModel.Set(this._rawBodyData, "auto_collection", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); - } + /// + /// Used to determine if invoices for this customer will be automatically issued. + /// If true, invoices will be automatically issued. If false, invoices will require + /// manual approval.If `null` is specified, the customer's auto issuance setting + /// will be inherited from the account-level setting. + /// + public bool? AutoIssuance + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_issuance"); } + init { JsonModel.Set(this._rawBodyData, "auto_issuance", value); } } public AddressInput? BillingAddress { get { - if (!this.BodyProperties.TryGetValue("billing_address", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["billing_address"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawBodyData, "billing_address"); } + init { JsonModel.Set(this._rawBodyData, "billing_address", value); } } /// - /// An ISO 4217 currency string used for the customer's invoices and balance. If - /// not set at creation time, will be set at subscription creation time. + /// An ISO 4217 currency string used for the customer's invoices and balance. + /// If not set at creation time, will be set at subscription creation time. /// public string? Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// @@ -120,55 +99,26 @@ public string? Currency /// public string? Email { - get - { - if (!this.BodyProperties.TryGetValue("email", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["email"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "email"); } + init { JsonModel.Set(this._rawBodyData, "email", value); } } public bool? EmailDelivery { - get - { - if (!this.BodyProperties.TryGetValue("email_delivery", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["email_delivery"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "email_delivery"); } + init { JsonModel.Set(this._rawBodyData, "email_delivery", value); } } /// - /// The external customer ID. This can only be set if empty and the customer has - /// no past or current subscriptions. + /// The external customer ID. This can only be set if the customer has no existing + /// external customer ID. Since this action may change usage quantities for all + /// existing subscriptions, it is disallowed if the customer has issued invoices + /// with usage line items and subject to the same restrictions as backdated subscription creation. /// public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } /// @@ -178,12 +128,12 @@ public CustomerHierarchyConfig? Hierarchy { get { - if (!this.BodyProperties.TryGetValue("hierarchy", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass( + this.RawBodyData, + "hierarchy" + ); } - set { this.BodyProperties["hierarchy"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "hierarchy", value); } } /// @@ -191,31 +141,41 @@ public CustomerHierarchyConfig? Hierarchy /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } /// /// The full name of the customer /// public string? Name + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } + } + + /// + /// Payment configuration for the customer, applicable when using Orb Invoicing + /// with a supported payment provider such as Stripe. + /// + public CustomerUpdateByExternalIDParamsPaymentConfiguration? PaymentConfiguration { get { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass( + this.RawBodyData, + "payment_configuration" + ); } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "payment_configuration", value); } } /// @@ -225,260 +185,1441 @@ public string? Name /// `bill.com`, `netsuite`), any product mappings must first be configured with /// the Orb team. /// - public CustomerUpdateByExternalIDParamsProperties::PaymentProvider? PaymentProvider + public ApiEnum? PaymentProvider { get { - if (!this.BodyProperties.TryGetValue("payment_provider", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawBodyData, "payment_provider"); + } + init { JsonModel.Set(this._rawBodyData, "payment_provider", value); } + } + + /// + /// The ID of this customer in an external payments solution, such as Stripe. + /// This is used for creating charges or invoices in the external system via Orb. + /// + public string? PaymentProviderID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "payment_provider_id"); } + init { JsonModel.Set(this._rawBodyData, "payment_provider_id", value); } + } - return Json::JsonSerializer.Deserialize( - element + public NewReportingConfiguration? ReportingConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawBodyData, + "reporting_configuration" ); } - set + init { JsonModel.Set(this._rawBodyData, "reporting_configuration", value); } + } + + public AddressInput? ShippingAddress + { + get + { + return JsonModel.GetNullableClass(this.RawBodyData, "shipping_address"); + } + init { JsonModel.Set(this._rawBodyData, "shipping_address", value); } + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration? TaxConfiguration + { + get { - this.BodyProperties["payment_provider"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawBodyData, + "tax_configuration" ); } + init { JsonModel.Set(this._rawBodyData, "tax_configuration", value); } } /// - /// The ID of this customer in an external payments solution, such as Stripe. This - /// is used for creating charges or invoices in the external system via Orb. + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. + /// + /// ### Supported Tax ID Countries and Types + /// + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | /// - public string? PaymentProviderID + public CustomerTaxID? TaxID { - get + get { return JsonModel.GetNullableClass(this.RawBodyData, "tax_id"); } + init { JsonModel.Set(this._rawBodyData, "tax_id", value); } + } + + public CustomerUpdateByExternalIDParams() { } + + public CustomerUpdateByExternalIDParams( + CustomerUpdateByExternalIDParams customerUpdateByExternalIDParams + ) + : base(customerUpdateByExternalIDParams) + { + this._rawBodyData = [.. customerUpdateByExternalIDParams._rawBodyData]; + } + + public CustomerUpdateByExternalIDParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateByExternalIDParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateByExternalIDParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format("/customers/external_customer_id/{0}", this.ID) + ) { - if ( - !this.BodyProperties.TryGetValue( - "payment_provider_id", - out Json::JsonElement element - ) - ) - return null; + Query = this.QueryString(options), + }.Uri; + } - return Json::JsonSerializer.Deserialize(element); - } - set + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - this.BodyProperties["payment_provider_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } +} - public NewReportingConfiguration? ReportingConfiguration +/// +/// Payment configuration for the customer, applicable when using Orb Invoicing with +/// a supported payment provider such as Stripe. +/// +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateByExternalIDParamsPaymentConfiguration, + CustomerUpdateByExternalIDParamsPaymentConfigurationFromRaw + >) +)] +public sealed record class CustomerUpdateByExternalIDParamsPaymentConfiguration : JsonModel +{ + /// + /// Provider-specific payment configuration. + /// + public IReadOnlyList? PaymentProviders { get { - if ( - !this.BodyProperties.TryGetValue( - "reporting_configuration", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass< + List + >(this.RawData, "payment_providers"); + } + init + { + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawData, "payment_providers", value); } - set + } + + /// + public override void Validate() + { + foreach (var item in this.PaymentProviders ?? []) { - this.BodyProperties["reporting_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + item.Validate(); } } - public AddressInput? ShippingAddress + public CustomerUpdateByExternalIDParamsPaymentConfiguration() { } + + public CustomerUpdateByExternalIDParamsPaymentConfiguration( + CustomerUpdateByExternalIDParamsPaymentConfiguration customerUpdateByExternalIDParamsPaymentConfiguration + ) + : base(customerUpdateByExternalIDParamsPaymentConfiguration) { } + + public CustomerUpdateByExternalIDParamsPaymentConfiguration( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateByExternalIDParamsPaymentConfiguration( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateByExternalIDParamsPaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerUpdateByExternalIDParamsPaymentConfigurationFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateByExternalIDParamsPaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateByExternalIDParamsPaymentConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderFromRaw + >) +)] +public sealed record class CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + : JsonModel +{ + /// + /// The payment provider to configure. + /// + public required ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > ProviderType { get { - if (!this.BodyProperties.TryGetValue("shipping_address", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullClass< + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > + >(this.RawData, "provider_type"); } - set + init { JsonModel.Set(this._rawData, "provider_type", value); } + } + + /// + /// List of Stripe payment method types to exclude for this customer. Excluded + /// payment methods will not be available for the customer to select during payment, + /// and will not be used for auto-collection. If a customer's default payment + /// method becomes excluded, Orb will attempt to use the next available compatible + /// payment method for auto-collection. + /// + public IReadOnlyList? ExcludedPaymentMethodTypes + { + get { - this.BodyProperties["shipping_address"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawData, + "excluded_payment_method_types" ); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "excluded_payment_method_types", value); + } } - public CustomerUpdateByExternalIDParamsProperties::TaxConfiguration? TaxConfiguration + /// + public override void Validate() { - get + this.ProviderType.Validate(); + _ = this.ExcludedPaymentMethodTypes; + } + + public CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider() { } + + public CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider( + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider customerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider + ) + : base(customerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider) { } + + public CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider( + ApiEnum< + string, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType + > providerType + ) + : this() + { + this.ProviderType = providerType; + } +} + +class CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProvider.FromRawUnchecked( + rawData + ); +} + +/// +/// The payment provider to configure. +/// +[JsonConverter( + typeof(CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderTypeConverter) +)] +public enum CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType +{ + Stripe, +} + +sealed class CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderTypeConverter + : JsonConverter +{ + public override CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - if ( - !this.BodyProperties.TryGetValue("tax_configuration", out Json::JsonElement element) - ) - return null; + "stripe" => + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + _ => (CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerUpdateByExternalIDParamsPaymentConfigurationPaymentProviderProviderType.Stripe => + "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// This is used for creating charges or invoices in an external system via Orb. +/// When not in test mode: - the connection must first be configured in the Orb webapp. +/// - if the provider is an invoicing provider (`stripe_invoice`, `quickbooks`, +/// `bill.com`, `netsuite`), any product mappings must first be configured with the +/// Orb team. +/// +[JsonConverter(typeof(CustomerUpdateByExternalIDParamsPaymentProviderConverter))] +public enum CustomerUpdateByExternalIDParamsPaymentProvider +{ + Quickbooks, + BillCom, + StripeCharge, + StripeInvoice, + Netsuite, +} + +sealed class CustomerUpdateByExternalIDParamsPaymentProviderConverter + : JsonConverter +{ + public override CustomerUpdateByExternalIDParamsPaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "quickbooks" => CustomerUpdateByExternalIDParamsPaymentProvider.Quickbooks, + "bill.com" => CustomerUpdateByExternalIDParamsPaymentProvider.BillCom, + "stripe_charge" => CustomerUpdateByExternalIDParamsPaymentProvider.StripeCharge, + "stripe_invoice" => CustomerUpdateByExternalIDParamsPaymentProvider.StripeInvoice, + "netsuite" => CustomerUpdateByExternalIDParamsPaymentProvider.Netsuite, + _ => (CustomerUpdateByExternalIDParamsPaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerUpdateByExternalIDParamsPaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerUpdateByExternalIDParamsPaymentProvider.Quickbooks => "quickbooks", + CustomerUpdateByExternalIDParamsPaymentProvider.BillCom => "bill.com", + CustomerUpdateByExternalIDParamsPaymentProvider.StripeCharge => "stripe_charge", + CustomerUpdateByExternalIDParamsPaymentProvider.StripeInvoice => "stripe_invoice", + CustomerUpdateByExternalIDParamsPaymentProvider.Netsuite => "netsuite", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CustomerUpdateByExternalIDParamsTaxConfigurationConverter))] +public record class CustomerUpdateByExternalIDParamsTaxConfiguration +{ + public object? Value { get; } = null; + + JsonElement? _element = null; - return Json::JsonSerializer.Deserialize( - element + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public bool TaxExempt + { + get + { + return Match( + newAvalara: (x) => x.TaxExempt, + newTaxJar: (x) => x.TaxExempt, + newSphere: (x) => x.TaxExempt, + numeral: (x) => x.TaxExempt, + anrok: (x) => x.TaxExempt, + stripe: (x) => x.TaxExempt ); } - set + } + + public bool? AutomaticTaxEnabled + { + get { - this.BodyProperties["tax_configuration"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newAvalara: (x) => x.AutomaticTaxEnabled, + newTaxJar: (x) => x.AutomaticTaxEnabled, + newSphere: (x) => x.AutomaticTaxEnabled, + numeral: (x) => x.AutomaticTaxEnabled, + anrok: (x) => x.AutomaticTaxEnabled, + stripe: (x) => x.AutomaticTaxEnabled ); } } + public CustomerUpdateByExternalIDParamsTaxConfiguration( + NewAvalaraTaxConfiguration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration( + NewTaxJarConfiguration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration( + NewSphereConfiguration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration( + CustomerUpdateByExternalIDParamsTaxConfigurationNumeral value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration( + CustomerUpdateByExternalIDParamsTaxConfigurationAnrok value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration( + CustomerUpdateByExternalIDParamsTaxConfigurationStripe value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateByExternalIDParamsTaxConfiguration(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAvalara(out var value)) { + /// // `value` is of type `NewAvalaraTaxConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAvalara([NotNullWhen(true)] out NewAvalaraTaxConfiguration? value) + { + value = this.Value as NewAvalaraTaxConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewTaxJar(out var value)) { + /// // `value` is of type `NewTaxJarConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewTaxJar([NotNullWhen(true)] out NewTaxJarConfiguration? value) + { + value = this.Value as NewTaxJarConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSphere(out var value)) { + /// // `value` is of type `NewSphereConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSphere([NotNullWhen(true)] out NewSphereConfiguration? value) + { + value = this.Value as NewSphereConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNumeral(out var value)) { + /// // `value` is of type `CustomerUpdateByExternalIDParamsTaxConfigurationNumeral` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNumeral( + [NotNullWhen(true)] out CustomerUpdateByExternalIDParamsTaxConfigurationNumeral? value + ) + { + value = this.Value as CustomerUpdateByExternalIDParamsTaxConfigurationNumeral; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAnrok(out var value)) { + /// // `value` is of type `CustomerUpdateByExternalIDParamsTaxConfigurationAnrok` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAnrok( + [NotNullWhen(true)] out CustomerUpdateByExternalIDParamsTaxConfigurationAnrok? value + ) + { + value = this.Value as CustomerUpdateByExternalIDParamsTaxConfigurationAnrok; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickStripe(out var value)) { + /// // `value` is of type `CustomerUpdateByExternalIDParamsTaxConfigurationStripe` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickStripe( + [NotNullWhen(true)] out CustomerUpdateByExternalIDParamsTaxConfigurationStripe? value + ) + { + value = this.Value as CustomerUpdateByExternalIDParamsTaxConfigurationStripe; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewAvalaraTaxConfiguration value) => {...}, + /// (NewTaxJarConfiguration value) => {...}, + /// (NewSphereConfiguration value) => {...}, + /// (CustomerUpdateByExternalIDParamsTaxConfigurationNumeral value) => {...}, + /// (CustomerUpdateByExternalIDParamsTaxConfigurationAnrok value) => {...}, + /// (CustomerUpdateByExternalIDParamsTaxConfigurationStripe value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newAvalara, + System::Action newTaxJar, + System::Action newSphere, + System::Action numeral, + System::Action anrok, + System::Action stripe + ) + { + switch (this.Value) + { + case NewAvalaraTaxConfiguration value: + newAvalara(value); + break; + case NewTaxJarConfiguration value: + newTaxJar(value); + break; + case NewSphereConfiguration value: + newSphere(value); + break; + case CustomerUpdateByExternalIDParamsTaxConfigurationNumeral value: + numeral(value); + break; + case CustomerUpdateByExternalIDParamsTaxConfigurationAnrok value: + anrok(value); + break; + case CustomerUpdateByExternalIDParamsTaxConfigurationStripe value: + stripe(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CustomerUpdateByExternalIDParamsTaxConfiguration" + ); + } + } + /// - /// Tax IDs are commonly required to be displayed on customer invoices, which are - /// added to the headers of invoices. + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. /// - /// ### Supported Tax ID Countries and Types + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// /// - /// | Country | Type | Description - /// | |----------------|--------------|---------------------------------------------| - /// | Andorra | `ad_nrt` | Andorran NRT Number - /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number - /// | | Australia | `au_abn` | Australian Business Number (AU ABN) - /// | | Australia | `au_arn` | Australian Taxation Office - /// Reference Number | | Austria | `eu_vat` | European VAT Number - /// | | Bahrain | `bh_vat` | Bahraini VAT Number - /// | | Belgium | `eu_vat` | European VAT Number - /// | | Bolivia | `bo_tin` | Bolivian Tax ID - /// | | Brazil | `br_cnpj` | Brazilian CNPJ - /// Number | | Brazil | `br_cpf` | Brazilian CPF - /// Number | | Bulgaria | `bg_uic` | Bulgaria - /// Unified Identification Code | | Bulgaria | `eu_vat` | European - /// VAT Number | | Canada | `ca_bn` | Canadian - /// BN | | Canada | `ca_gst_hst` | Canadian - /// GST/HST Number | | Canada | `ca_pst_bc` | Canadian - /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian - /// PST Number (Manitoba) | | Canada | `ca_pst_sk` | Canadian - /// PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian - /// QST Number (Québec) | | Chile | `cl_tin` | Chilean - /// TIN | | China | `cn_tin` | Chinese - /// Tax ID | | Colombia | `co_nit` | Colombian - /// NIT Number | | Costa Rica | `cr_tin` | Costa - /// Rican Tax ID | | Croatia | `eu_vat` | European - /// VAT Number | | Cyprus | `eu_vat` | European - /// VAT Number | | Czech Republic | `eu_vat` | European - /// VAT Number | | Denmark | `eu_vat` | European - /// VAT Number | | Dominican Republic | `do_rcn` | Dominican - /// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian - /// RUC Number | | Egypt | `eg_tin` | Egyptian - /// Tax Identification Number | | El Salvador | `sv_nit` - /// | El Salvadorian NIT Number | | Estonia | `eu_vat` | - /// European VAT Number | | EU | `eu_oss_vat` | European One Stop Shop - /// VAT Number for non-Union scheme | | Finland | `eu_vat` | European VAT - /// Number | | France | `eu_vat` | European - /// VAT Number | | Georgia | `ge_vat` | - /// Georgian VAT | | Germany | `eu_vat` - /// | European VAT Number | | Greece - /// | `eu_vat` | European VAT Number | | - /// Hong Kong | `hk_br` | Hong Kong BR Number - /// | | Hungary | `eu_vat` | European VAT Number - /// | | Hungary | `hu_tin` | Hungary Tax Number (adószám) - /// | | Iceland | `is_vat` | Icelandic VAT - /// | | India | `in_gst` | Indian GST - /// Number | | Indonesia | `id_npwp` | Indonesian - /// NPWP Number | | Ireland | `eu_vat` | - /// European VAT Number | | Israel | `il_vat` - /// | Israel VAT | | Italy - /// | `eu_vat` | European VAT Number | | - /// Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) - /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' - /// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | - /// Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) - /// | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification - /// Number | | Kenya | `ke_pin` | Kenya Revenue Authority - /// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number - /// | | Liechtenstein | `li_uid` | Liechtensteinian - /// UID Number | | Lithuania | `eu_vat` | European VAT Number - /// | | Luxembourg | `eu_vat` | European VAT Number - /// | | Malaysia | `my_frp` | Malaysian FRP Number - /// | | Malaysia | `my_itn` | Malaysian ITN - /// | | Malaysia | `my_sst` | Malaysian SST Number | - /// | Malta | `eu_vat ` | European VAT Number | | Mexico - /// | `mx_rfc` | Mexican RFC Number | | Netherlands - /// | `eu_vat` | European VAT Number | | New Zealand | - /// `nz_gst` | New Zealand GST Number | | Nigeria | - /// `ng_tin` | Nigerian Tax Identification Number | | Norway | `no_vat` - /// | Norwegian VAT Number | | Norway | `no_voec` | Norwegian - /// VAT on e-commerce Number | | Oman | `om_vat` | Omani VAT Number - /// | | Peru | `pe_ruc` | Peruvian RUC Number - /// | | Philippines | `ph_tin ` | Philippines Tax Identification - /// Number | | Poland | `eu_vat` | European VAT Number - /// | | Portugal | `eu_vat` | European VAT Number | | - /// Romania | `eu_vat` | European VAT Number | | Romania - /// | `ro_tin` | Romanian Tax ID Number | | Russia - /// | `ru_inn` | Russian INN | | Russia | `ru_kpp` - /// | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi - /// Arabia VAT | | Serbia | `rs_pib` | Serbian PIB - /// Number | | Singapore | `sg_gst` | Singaporean GST - /// | | Singapore | `sg_uen` | Singaporean UEN - /// | | Slovakia | `eu_vat` | European VAT Number - /// | | Slovenia | `eu_vat` | European VAT Number - /// | | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) - /// | | South Africa | `za_vat` | South African VAT - /// Number | | South Korea | `kr_brn` | Korean - /// BRN | | Spain | `es_cif` - /// | Spanish NIF Number (previously Spanish CIF Number) | | Spain - /// | `eu_vat` | European VAT Number | | - /// Sweden | `eu_vat` | European VAT Number - /// | | Switzerland | `ch_vat` | Switzerland VAT Number - /// | | Taiwan | `tw_vat` | Taiwanese VAT - /// | | Thailand | `th_vat` | - /// Thai VAT | | Turkey - /// | `tr_tin` | Turkish Tax Identification Number | | Ukraine - /// | `ua_vat` | Ukrainian VAT - /// | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN - /// | | United Kingdom | `eu_vat` | Northern Ireland - /// VAT Number | | United Kingdom | `gb_vat` | United - /// Kingdom VAT Number | | United States | `us_ein` - /// | United States EIN | | Uruguay - /// | `uy_ruc` | Uruguayan RUC Number | | Venezuela - /// | `ve_rif` | Venezuelan RIF Number - /// | | Vietnam | `vn_tin` | Vietnamese Tax ID Number - /// | + /// + /// + /// var result = instance.Match( + /// (NewAvalaraTaxConfiguration value) => {...}, + /// (NewTaxJarConfiguration value) => {...}, + /// (NewSphereConfiguration value) => {...}, + /// (CustomerUpdateByExternalIDParamsTaxConfigurationNumeral value) => {...}, + /// (CustomerUpdateByExternalIDParamsTaxConfigurationAnrok value) => {...}, + /// (CustomerUpdateByExternalIDParamsTaxConfigurationStripe value) => {...} + /// ); + /// + /// /// - public Models::CustomerTaxID? TaxID + public T Match( + System::Func newAvalara, + System::Func newTaxJar, + System::Func newSphere, + System::Func numeral, + System::Func anrok, + System::Func stripe + ) { - get + return this.Value switch + { + NewAvalaraTaxConfiguration value => newAvalara(value), + NewTaxJarConfiguration value => newTaxJar(value), + NewSphereConfiguration value => newSphere(value), + CustomerUpdateByExternalIDParamsTaxConfigurationNumeral value => numeral(value), + CustomerUpdateByExternalIDParamsTaxConfigurationAnrok value => anrok(value), + CustomerUpdateByExternalIDParamsTaxConfigurationStripe value => stripe(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CustomerUpdateByExternalIDParamsTaxConfiguration" + ), + }; + } + + public static implicit operator CustomerUpdateByExternalIDParamsTaxConfiguration( + NewAvalaraTaxConfiguration value + ) => new(value); + + public static implicit operator CustomerUpdateByExternalIDParamsTaxConfiguration( + NewTaxJarConfiguration value + ) => new(value); + + public static implicit operator CustomerUpdateByExternalIDParamsTaxConfiguration( + NewSphereConfiguration value + ) => new(value); + + public static implicit operator CustomerUpdateByExternalIDParamsTaxConfiguration( + CustomerUpdateByExternalIDParamsTaxConfigurationNumeral value + ) => new(value); + + public static implicit operator CustomerUpdateByExternalIDParamsTaxConfiguration( + CustomerUpdateByExternalIDParamsTaxConfigurationAnrok value + ) => new(value); + + public static implicit operator CustomerUpdateByExternalIDParamsTaxConfiguration( + CustomerUpdateByExternalIDParamsTaxConfigurationStripe value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) { - if (!this.BodyProperties.TryGetValue("tax_id", out Json::JsonElement element)) - return null; + throw new OrbInvalidDataException( + "Data did not match any variant of CustomerUpdateByExternalIDParamsTaxConfiguration" + ); + } + this.Switch( + (newAvalara) => newAvalara.Validate(), + (newTaxJar) => newTaxJar.Validate(), + (newSphere) => newSphere.Validate(), + (numeral) => numeral.Validate(), + (anrok) => anrok.Validate(), + (stripe) => stripe.Validate() + ); + } + + public virtual bool Equals(CustomerUpdateByExternalIDParamsTaxConfiguration? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CustomerUpdateByExternalIDParamsTaxConfigurationConverter + : JsonConverter +{ + public override CustomerUpdateByExternalIDParamsTaxConfiguration? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? taxProvider; + try + { + taxProvider = element.GetProperty("tax_provider").GetString(); + } + catch + { + taxProvider = null; + } + + switch (taxProvider) + { + case "avalara": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "taxjar": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } - return Json::JsonSerializer.Deserialize(element); + return new(element); + } + case "sphere": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "numeral": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "anrok": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "stripe": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new CustomerUpdateByExternalIDParamsTaxConfiguration(element); + } } - set { this.BodyProperties["tax_id"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public override void Write( + Utf8JsonWriter writer, + CustomerUpdateByExternalIDParamsTaxConfiguration? value, + JsonSerializerOptions options + ) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') - + string.Format("/customers/external_customer_id/{0}", this.ID) + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateByExternalIDParamsTaxConfigurationNumeral, + CustomerUpdateByExternalIDParamsTaxConfigurationNumeralFromRaw + >) +)] +public sealed record class CustomerUpdateByExternalIDParamsTaxConfigurationNumeral : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"numeral\"") + ) ) { - Query = this.QueryString(client), - }.Uri; + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.AutomaticTaxEnabled; } - public Http::StringContent BodyContent() + public CustomerUpdateByExternalIDParamsTaxConfigurationNumeral() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this.TaxProvider = JsonSerializer.Deserialize("\"numeral\""); + } + + public CustomerUpdateByExternalIDParamsTaxConfigurationNumeral( + CustomerUpdateByExternalIDParamsTaxConfigurationNumeral customerUpdateByExternalIDParamsTaxConfigurationNumeral + ) + : base(customerUpdateByExternalIDParamsTaxConfigurationNumeral) { } + + public CustomerUpdateByExternalIDParamsTaxConfigurationNumeral( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"numeral\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateByExternalIDParamsTaxConfigurationNumeral( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateByExternalIDParamsTaxConfigurationNumeral FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateByExternalIDParamsTaxConfigurationNumeral(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; + } +} + +class CustomerUpdateByExternalIDParamsTaxConfigurationNumeralFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateByExternalIDParamsTaxConfigurationNumeral FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateByExternalIDParamsTaxConfigurationNumeral.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateByExternalIDParamsTaxConfigurationAnrok, + CustomerUpdateByExternalIDParamsTaxConfigurationAnrokFromRaw + >) +)] +public sealed record class CustomerUpdateByExternalIDParamsTaxConfigurationAnrok : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"anrok\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.AutomaticTaxEnabled; + } + + public CustomerUpdateByExternalIDParamsTaxConfigurationAnrok() + { + this.TaxProvider = JsonSerializer.Deserialize("\"anrok\""); + } + + public CustomerUpdateByExternalIDParamsTaxConfigurationAnrok( + CustomerUpdateByExternalIDParamsTaxConfigurationAnrok customerUpdateByExternalIDParamsTaxConfigurationAnrok + ) + : base(customerUpdateByExternalIDParamsTaxConfigurationAnrok) { } + + public CustomerUpdateByExternalIDParamsTaxConfigurationAnrok( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"anrok\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateByExternalIDParamsTaxConfigurationAnrok( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateByExternalIDParamsTaxConfigurationAnrok FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateByExternalIDParamsTaxConfigurationAnrok(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; + } +} + +class CustomerUpdateByExternalIDParamsTaxConfigurationAnrokFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateByExternalIDParamsTaxConfigurationAnrok FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateByExternalIDParamsTaxConfigurationAnrok.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateByExternalIDParamsTaxConfigurationStripe, + CustomerUpdateByExternalIDParamsTaxConfigurationStripeFromRaw + >) +)] +public sealed record class CustomerUpdateByExternalIDParamsTaxConfigurationStripe : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"stripe\"") + ) + ) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + throw new OrbInvalidDataException("Invalid value given for constant"); } + _ = this.AutomaticTaxEnabled; + } + + public CustomerUpdateByExternalIDParamsTaxConfigurationStripe() + { + this.TaxProvider = JsonSerializer.Deserialize("\"stripe\""); + } + + public CustomerUpdateByExternalIDParamsTaxConfigurationStripe( + CustomerUpdateByExternalIDParamsTaxConfigurationStripe customerUpdateByExternalIDParamsTaxConfigurationStripe + ) + : base(customerUpdateByExternalIDParamsTaxConfigurationStripe) { } + + public CustomerUpdateByExternalIDParamsTaxConfigurationStripe( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"stripe\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateByExternalIDParamsTaxConfigurationStripe( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateByExternalIDParamsTaxConfigurationStripe FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateByExternalIDParamsTaxConfigurationStripe(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; } } + +class CustomerUpdateByExternalIDParamsTaxConfigurationStripeFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateByExternalIDParamsTaxConfigurationStripe FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateByExternalIDParamsTaxConfigurationStripe.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/PaymentProvider.cs b/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/PaymentProvider.cs deleted file mode 100644 index 850700cd..00000000 --- a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/PaymentProvider.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties; - -/// -/// This is used for creating charges or invoices in an external system via Orb. When -/// not in test mode: - the connection must first be configured in the Orb webapp. -/// - if the provider is an invoicing provider (`stripe_invoice`, `quickbooks`, `bill.com`, -/// `netsuite`), any product mappings must first be configured with the Orb team. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PaymentProvider(string value) : Orb::IEnum -{ - public static readonly PaymentProvider Quickbooks = new("quickbooks"); - - public static readonly PaymentProvider BillCom = new("bill.com"); - - public static readonly PaymentProvider StripeCharge = new("stripe_charge"); - - public static readonly PaymentProvider StripeInvoice = new("stripe_invoice"); - - public static readonly PaymentProvider Netsuite = new("netsuite"); - - readonly string _value = value; - - public enum Value - { - Quickbooks, - BillCom, - StripeCharge, - StripeInvoice, - Netsuite, - } - - public Value Known() => - _value switch - { - "quickbooks" => Value.Quickbooks, - "bill.com" => Value.BillCom, - "stripe_charge" => Value.StripeCharge, - "stripe_invoice" => Value.StripeInvoice, - "netsuite" => Value.Netsuite, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PaymentProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/TaxConfiguration.cs b/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/TaxConfiguration.cs deleted file mode 100644 index d30dd455..00000000 --- a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/TaxConfiguration.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Customers = Orb.Models.Customers; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TaxConfigurationVariants = Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties.TaxConfigurationVariants; - -namespace Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class TaxConfiguration -{ - internal TaxConfiguration() { } - - public static TaxConfigurationVariants::NewAvalaraTaxConfiguration Create( - Customers::NewAvalaraTaxConfiguration value - ) => new(value); - - public static TaxConfigurationVariants::NewTaxJarConfiguration Create( - Customers::NewTaxJarConfiguration value - ) => new(value); - - public static TaxConfigurationVariants::NewSphereConfiguration Create( - Customers::NewSphereConfiguration value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/TaxConfigurationVariants/All.cs b/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/TaxConfigurationVariants/All.cs deleted file mode 100644 index 43c434bd..00000000 --- a/src/Orb/Models/Customers/CustomerUpdateByExternalIDParamsProperties/TaxConfigurationVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Customers = Orb.Models.Customers; -using CustomerUpdateByExternalIDParamsProperties = Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.CustomerUpdateByExternalIDParamsProperties.TaxConfigurationVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAvalaraTaxConfiguration(Customers::NewAvalaraTaxConfiguration Value) - : CustomerUpdateByExternalIDParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewAvalaraTaxConfiguration From(Customers::NewAvalaraTaxConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewTaxJarConfiguration(Customers::NewTaxJarConfiguration Value) - : CustomerUpdateByExternalIDParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewTaxJarConfiguration From(Customers::NewTaxJarConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSphereConfiguration(Customers::NewSphereConfiguration Value) - : CustomerUpdateByExternalIDParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewSphereConfiguration From(Customers::NewSphereConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/CustomerUpdateParams.cs b/src/Orb/Models/Customers/CustomerUpdateParams.cs index 8899481e..302fe3db 100644 --- a/src/Orb/Models/Customers/CustomerUpdateParams.cs +++ b/src/Orb/Models/Customers/CustomerUpdateParams.cs @@ -1,11 +1,13 @@ -using CustomerUpdateParamsProperties = Orb.Models.Customers.CustomerUpdateParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Customers; @@ -15,54 +17,40 @@ namespace Orb.Models.Customers; /// `billing_address`, and `additional_emails` of an existing customer. Other fields /// on a customer are currently immutable. /// -public sealed record class CustomerUpdateParams : Orb::ParamsBase +public sealed record class CustomerUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string CustomerID; + public string? CustomerID { get; init; } public NewAccountingSyncConfiguration? AccountingSyncConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "accounting_sync_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["accounting_sync_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawBodyData, + "accounting_sync_configuration" + ); } + init { JsonModel.Set(this._rawBodyData, "accounting_sync_configuration", value); } } /// /// Additional email addresses for this customer. If populated, these email addresses - /// will be CC'd for customer communications. + /// will be CC'd for customer communications. The total number of email addresses + /// (including the primary email) cannot exceed 50. /// - public Generic::List? AdditionalEmails + public IReadOnlyList? AdditionalEmails { get { - if ( - !this.BodyProperties.TryGetValue("additional_emails", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.BodyProperties["additional_emails"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawBodyData, "additional_emails"); } + init { JsonModel.Set(this._rawBodyData, "additional_emails", value); } } /// @@ -72,48 +60,39 @@ public NewAccountingSyncConfiguration? AccountingSyncConfiguration /// public bool? AutoCollection { - get - { - if (!this.BodyProperties.TryGetValue("auto_collection", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_collection"); } + init { JsonModel.Set(this._rawBodyData, "auto_collection", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); - } + /// + /// Used to determine if invoices for this customer will be automatically issued. + /// If true, invoices will be automatically issued. If false, invoices will require + /// manual approval.If `null` is specified, the customer's auto issuance setting + /// will be inherited from the account-level setting. + /// + public bool? AutoIssuance + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_issuance"); } + init { JsonModel.Set(this._rawBodyData, "auto_issuance", value); } } public AddressInput? BillingAddress { get { - if (!this.BodyProperties.TryGetValue("billing_address", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["billing_address"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawBodyData, "billing_address"); } + init { JsonModel.Set(this._rawBodyData, "billing_address", value); } } /// - /// An ISO 4217 currency string used for the customer's invoices and balance. If - /// not set at creation time, will be set at subscription creation time. + /// An ISO 4217 currency string used for the customer's invoices and balance. + /// If not set at creation time, will be set at subscription creation time. /// public string? Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// @@ -121,55 +100,26 @@ public string? Currency /// public string? Email { - get - { - if (!this.BodyProperties.TryGetValue("email", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["email"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "email"); } + init { JsonModel.Set(this._rawBodyData, "email", value); } } public bool? EmailDelivery { - get - { - if (!this.BodyProperties.TryGetValue("email_delivery", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["email_delivery"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "email_delivery"); } + init { JsonModel.Set(this._rawBodyData, "email_delivery", value); } } /// - /// The external customer ID. This can only be set if empty and the customer has - /// no past or current subscriptions. + /// The external customer ID. This can only be set if the customer has no existing + /// external customer ID. Since this action may change usage quantities for all + /// existing subscriptions, it is disallowed if the customer has issued invoices + /// with usage line items and subject to the same restrictions as backdated subscription creation. /// public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } /// @@ -179,12 +129,12 @@ public CustomerHierarchyConfig? Hierarchy { get { - if (!this.BodyProperties.TryGetValue("hierarchy", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass( + this.RawBodyData, + "hierarchy" + ); } - set { this.BodyProperties["hierarchy"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "hierarchy", value); } } /// @@ -192,31 +142,41 @@ public CustomerHierarchyConfig? Hierarchy /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } /// /// The full name of the customer /// public string? Name + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } + } + + /// + /// Payment configuration for the customer, applicable when using Orb Invoicing + /// with a supported payment provider such as Stripe. + /// + public CustomerUpdateParamsPaymentConfiguration? PaymentConfiguration { get { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass( + this.RawBodyData, + "payment_configuration" + ); } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "payment_configuration", value); } } /// @@ -226,260 +186,1422 @@ public string? Name /// `bill.com`, `netsuite`), any product mappings must first be configured with /// the Orb team. /// - public CustomerUpdateParamsProperties::PaymentProvider? PaymentProvider + public ApiEnum? PaymentProvider { get { - if (!this.BodyProperties.TryGetValue("payment_provider", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.BodyProperties["payment_provider"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "payment_provider" ); } + init { JsonModel.Set(this._rawBodyData, "payment_provider", value); } } /// - /// The ID of this customer in an external payments solution, such as Stripe. This - /// is used for creating charges or invoices in the external system via Orb. + /// The ID of this customer in an external payments solution, such as Stripe. + /// This is used for creating charges or invoices in the external system via Orb. /// public string? PaymentProviderID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "payment_provider_id"); } + init { JsonModel.Set(this._rawBodyData, "payment_provider_id", value); } + } + + public NewReportingConfiguration? ReportingConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "payment_provider_id", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass( + this.RawBodyData, + "reporting_configuration" + ); + } + init { JsonModel.Set(this._rawBodyData, "reporting_configuration", value); } + } - return Json::JsonSerializer.Deserialize(element); + public AddressInput? ShippingAddress + { + get + { + return JsonModel.GetNullableClass(this.RawBodyData, "shipping_address"); } - set + init { JsonModel.Set(this._rawBodyData, "shipping_address", value); } + } + + public CustomerUpdateParamsTaxConfiguration? TaxConfiguration + { + get { - this.BodyProperties["payment_provider_id"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawBodyData, + "tax_configuration" ); } + init { JsonModel.Set(this._rawBodyData, "tax_configuration", value); } } - public NewReportingConfiguration? ReportingConfiguration + /// + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. + /// + /// ### Supported Tax ID Countries and Types + /// + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | + /// + public CustomerTaxID? TaxID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "tax_id"); } + init { JsonModel.Set(this._rawBodyData, "tax_id", value); } + } + + public CustomerUpdateParams() { } + + public CustomerUpdateParams(CustomerUpdateParams customerUpdateParams) + : base(customerUpdateParams) + { + this._rawBodyData = [.. customerUpdateParams._rawBodyData]; + } + + public CustomerUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format("/customers/{0}", this.CustomerID) + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +/// +/// Payment configuration for the customer, applicable when using Orb Invoicing with +/// a supported payment provider such as Stripe. +/// +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateParamsPaymentConfiguration, + CustomerUpdateParamsPaymentConfigurationFromRaw + >) +)] +public sealed record class CustomerUpdateParamsPaymentConfiguration : JsonModel +{ + /// + /// Provider-specific payment configuration. + /// + public IReadOnlyList? PaymentProviders { get { - if ( - !this.BodyProperties.TryGetValue( - "reporting_configuration", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass< + List + >(this.RawData, "payment_providers"); + } + init + { + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawData, "payment_providers", value); } - set + } + + /// + public override void Validate() + { + foreach (var item in this.PaymentProviders ?? []) { - this.BodyProperties["reporting_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + item.Validate(); } } - public AddressInput? ShippingAddress + public CustomerUpdateParamsPaymentConfiguration() { } + + public CustomerUpdateParamsPaymentConfiguration( + CustomerUpdateParamsPaymentConfiguration customerUpdateParamsPaymentConfiguration + ) + : base(customerUpdateParamsPaymentConfiguration) { } + + public CustomerUpdateParamsPaymentConfiguration( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateParamsPaymentConfiguration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateParamsPaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerUpdateParamsPaymentConfigurationFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateParamsPaymentConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateParamsPaymentConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateParamsPaymentConfigurationPaymentProvider, + CustomerUpdateParamsPaymentConfigurationPaymentProviderFromRaw + >) +)] +public sealed record class CustomerUpdateParamsPaymentConfigurationPaymentProvider : JsonModel +{ + /// + /// The payment provider to configure. + /// + public required ApiEnum< + string, + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType + > ProviderType { get { - if (!this.BodyProperties.TryGetValue("shipping_address", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "provider_type"); } - set + init { JsonModel.Set(this._rawData, "provider_type", value); } + } + + /// + /// List of Stripe payment method types to exclude for this customer. Excluded + /// payment methods will not be available for the customer to select during payment, + /// and will not be used for auto-collection. If a customer's default payment + /// method becomes excluded, Orb will attempt to use the next available compatible + /// payment method for auto-collection. + /// + public IReadOnlyList? ExcludedPaymentMethodTypes + { + get { - this.BodyProperties["shipping_address"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawData, + "excluded_payment_method_types" ); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "excluded_payment_method_types", value); + } } - public CustomerUpdateParamsProperties::TaxConfiguration? TaxConfiguration + /// + public override void Validate() { - get + this.ProviderType.Validate(); + _ = this.ExcludedPaymentMethodTypes; + } + + public CustomerUpdateParamsPaymentConfigurationPaymentProvider() { } + + public CustomerUpdateParamsPaymentConfigurationPaymentProvider( + CustomerUpdateParamsPaymentConfigurationPaymentProvider customerUpdateParamsPaymentConfigurationPaymentProvider + ) + : base(customerUpdateParamsPaymentConfigurationPaymentProvider) { } + + public CustomerUpdateParamsPaymentConfigurationPaymentProvider( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateParamsPaymentConfigurationPaymentProvider( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateParamsPaymentConfigurationPaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateParamsPaymentConfigurationPaymentProvider( + ApiEnum< + string, + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType + > providerType + ) + : this() + { + this.ProviderType = providerType; + } +} + +class CustomerUpdateParamsPaymentConfigurationPaymentProviderFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateParamsPaymentConfigurationPaymentProvider FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateParamsPaymentConfigurationPaymentProvider.FromRawUnchecked(rawData); +} + +/// +/// The payment provider to configure. +/// +[JsonConverter( + typeof(CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderTypeConverter) +)] +public enum CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType +{ + Stripe, +} + +sealed class CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderTypeConverter + : JsonConverter +{ + public override CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - if ( - !this.BodyProperties.TryGetValue("tax_configuration", out Json::JsonElement element) - ) - return null; + "stripe" => CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe, + _ => (CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerUpdateParamsPaymentConfigurationPaymentProviderProviderType.Stripe => + "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// This is used for creating charges or invoices in an external system via Orb. +/// When not in test mode: - the connection must first be configured in the Orb webapp. +/// - if the provider is an invoicing provider (`stripe_invoice`, `quickbooks`, +/// `bill.com`, `netsuite`), any product mappings must first be configured with the +/// Orb team. +/// +[JsonConverter(typeof(CustomerUpdateParamsPaymentProviderConverter))] +public enum CustomerUpdateParamsPaymentProvider +{ + Quickbooks, + BillCom, + StripeCharge, + StripeInvoice, + Netsuite, +} + +sealed class CustomerUpdateParamsPaymentProviderConverter + : JsonConverter +{ + public override CustomerUpdateParamsPaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "quickbooks" => CustomerUpdateParamsPaymentProvider.Quickbooks, + "bill.com" => CustomerUpdateParamsPaymentProvider.BillCom, + "stripe_charge" => CustomerUpdateParamsPaymentProvider.StripeCharge, + "stripe_invoice" => CustomerUpdateParamsPaymentProvider.StripeInvoice, + "netsuite" => CustomerUpdateParamsPaymentProvider.Netsuite, + _ => (CustomerUpdateParamsPaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CustomerUpdateParamsPaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CustomerUpdateParamsPaymentProvider.Quickbooks => "quickbooks", + CustomerUpdateParamsPaymentProvider.BillCom => "bill.com", + CustomerUpdateParamsPaymentProvider.StripeCharge => "stripe_charge", + CustomerUpdateParamsPaymentProvider.StripeInvoice => "stripe_invoice", + CustomerUpdateParamsPaymentProvider.Netsuite => "netsuite", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CustomerUpdateParamsTaxConfigurationConverter))] +public record class CustomerUpdateParamsTaxConfiguration +{ + public object? Value { get; } = null; + + JsonElement? _element = null; - return Json::JsonSerializer.Deserialize( - element + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public bool TaxExempt + { + get + { + return Match( + newAvalara: (x) => x.TaxExempt, + newTaxJar: (x) => x.TaxExempt, + newSphere: (x) => x.TaxExempt, + numeral: (x) => x.TaxExempt, + anrok: (x) => x.TaxExempt, + stripe: (x) => x.TaxExempt ); } - set + } + + public bool? AutomaticTaxEnabled + { + get { - this.BodyProperties["tax_configuration"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newAvalara: (x) => x.AutomaticTaxEnabled, + newTaxJar: (x) => x.AutomaticTaxEnabled, + newSphere: (x) => x.AutomaticTaxEnabled, + numeral: (x) => x.AutomaticTaxEnabled, + anrok: (x) => x.AutomaticTaxEnabled, + stripe: (x) => x.AutomaticTaxEnabled ); } } + public CustomerUpdateParamsTaxConfiguration( + NewAvalaraTaxConfiguration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateParamsTaxConfiguration( + NewTaxJarConfiguration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateParamsTaxConfiguration( + NewSphereConfiguration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateParamsTaxConfiguration( + CustomerUpdateParamsTaxConfigurationNumeral value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateParamsTaxConfiguration( + CustomerUpdateParamsTaxConfigurationAnrok value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateParamsTaxConfiguration( + CustomerUpdateParamsTaxConfigurationStripe value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CustomerUpdateParamsTaxConfiguration(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAvalara(out var value)) { + /// // `value` is of type `NewAvalaraTaxConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAvalara([NotNullWhen(true)] out NewAvalaraTaxConfiguration? value) + { + value = this.Value as NewAvalaraTaxConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewTaxJar(out var value)) { + /// // `value` is of type `NewTaxJarConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewTaxJar([NotNullWhen(true)] out NewTaxJarConfiguration? value) + { + value = this.Value as NewTaxJarConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSphere(out var value)) { + /// // `value` is of type `NewSphereConfiguration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSphere([NotNullWhen(true)] out NewSphereConfiguration? value) + { + value = this.Value as NewSphereConfiguration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNumeral(out var value)) { + /// // `value` is of type `CustomerUpdateParamsTaxConfigurationNumeral` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNumeral( + [NotNullWhen(true)] out CustomerUpdateParamsTaxConfigurationNumeral? value + ) + { + value = this.Value as CustomerUpdateParamsTaxConfigurationNumeral; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAnrok(out var value)) { + /// // `value` is of type `CustomerUpdateParamsTaxConfigurationAnrok` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAnrok( + [NotNullWhen(true)] out CustomerUpdateParamsTaxConfigurationAnrok? value + ) + { + value = this.Value as CustomerUpdateParamsTaxConfigurationAnrok; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickStripe(out var value)) { + /// // `value` is of type `CustomerUpdateParamsTaxConfigurationStripe` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickStripe( + [NotNullWhen(true)] out CustomerUpdateParamsTaxConfigurationStripe? value + ) + { + value = this.Value as CustomerUpdateParamsTaxConfigurationStripe; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewAvalaraTaxConfiguration value) => {...}, + /// (NewTaxJarConfiguration value) => {...}, + /// (NewSphereConfiguration value) => {...}, + /// (CustomerUpdateParamsTaxConfigurationNumeral value) => {...}, + /// (CustomerUpdateParamsTaxConfigurationAnrok value) => {...}, + /// (CustomerUpdateParamsTaxConfigurationStripe value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newAvalara, + System::Action newTaxJar, + System::Action newSphere, + System::Action numeral, + System::Action anrok, + System::Action stripe + ) + { + switch (this.Value) + { + case NewAvalaraTaxConfiguration value: + newAvalara(value); + break; + case NewTaxJarConfiguration value: + newTaxJar(value); + break; + case NewSphereConfiguration value: + newSphere(value); + break; + case CustomerUpdateParamsTaxConfigurationNumeral value: + numeral(value); + break; + case CustomerUpdateParamsTaxConfigurationAnrok value: + anrok(value); + break; + case CustomerUpdateParamsTaxConfigurationStripe value: + stripe(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CustomerUpdateParamsTaxConfiguration" + ); + } + } + /// - /// Tax IDs are commonly required to be displayed on customer invoices, which are - /// added to the headers of invoices. + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. /// - /// ### Supported Tax ID Countries and Types + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// /// - /// | Country | Type | Description - /// | |----------------|--------------|---------------------------------------------| - /// | Andorra | `ad_nrt` | Andorran NRT Number - /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number - /// | | Australia | `au_abn` | Australian Business Number (AU ABN) - /// | | Australia | `au_arn` | Australian Taxation Office - /// Reference Number | | Austria | `eu_vat` | European VAT Number - /// | | Bahrain | `bh_vat` | Bahraini VAT Number - /// | | Belgium | `eu_vat` | European VAT Number - /// | | Bolivia | `bo_tin` | Bolivian Tax ID - /// | | Brazil | `br_cnpj` | Brazilian CNPJ - /// Number | | Brazil | `br_cpf` | Brazilian CPF - /// Number | | Bulgaria | `bg_uic` | Bulgaria - /// Unified Identification Code | | Bulgaria | `eu_vat` | European - /// VAT Number | | Canada | `ca_bn` | Canadian - /// BN | | Canada | `ca_gst_hst` | Canadian - /// GST/HST Number | | Canada | `ca_pst_bc` | Canadian - /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian - /// PST Number (Manitoba) | | Canada | `ca_pst_sk` | Canadian - /// PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian - /// QST Number (Québec) | | Chile | `cl_tin` | Chilean - /// TIN | | China | `cn_tin` | Chinese - /// Tax ID | | Colombia | `co_nit` | Colombian - /// NIT Number | | Costa Rica | `cr_tin` | Costa - /// Rican Tax ID | | Croatia | `eu_vat` | European - /// VAT Number | | Cyprus | `eu_vat` | European - /// VAT Number | | Czech Republic | `eu_vat` | European - /// VAT Number | | Denmark | `eu_vat` | European - /// VAT Number | | Dominican Republic | `do_rcn` | Dominican - /// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian - /// RUC Number | | Egypt | `eg_tin` | Egyptian - /// Tax Identification Number | | El Salvador | `sv_nit` - /// | El Salvadorian NIT Number | | Estonia | `eu_vat` | - /// European VAT Number | | EU | `eu_oss_vat` | European One Stop Shop - /// VAT Number for non-Union scheme | | Finland | `eu_vat` | European VAT - /// Number | | France | `eu_vat` | European - /// VAT Number | | Georgia | `ge_vat` | - /// Georgian VAT | | Germany | `eu_vat` - /// | European VAT Number | | Greece - /// | `eu_vat` | European VAT Number | | - /// Hong Kong | `hk_br` | Hong Kong BR Number - /// | | Hungary | `eu_vat` | European VAT Number - /// | | Hungary | `hu_tin` | Hungary Tax Number (adószám) - /// | | Iceland | `is_vat` | Icelandic VAT - /// | | India | `in_gst` | Indian GST - /// Number | | Indonesia | `id_npwp` | Indonesian - /// NPWP Number | | Ireland | `eu_vat` | - /// European VAT Number | | Israel | `il_vat` - /// | Israel VAT | | Italy - /// | `eu_vat` | European VAT Number | | - /// Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) - /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' - /// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | - /// Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) - /// | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification - /// Number | | Kenya | `ke_pin` | Kenya Revenue Authority - /// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number - /// | | Liechtenstein | `li_uid` | Liechtensteinian - /// UID Number | | Lithuania | `eu_vat` | European VAT Number - /// | | Luxembourg | `eu_vat` | European VAT Number - /// | | Malaysia | `my_frp` | Malaysian FRP Number - /// | | Malaysia | `my_itn` | Malaysian ITN - /// | | Malaysia | `my_sst` | Malaysian SST Number | - /// | Malta | `eu_vat ` | European VAT Number | | Mexico - /// | `mx_rfc` | Mexican RFC Number | | Netherlands - /// | `eu_vat` | European VAT Number | | New Zealand | - /// `nz_gst` | New Zealand GST Number | | Nigeria | - /// `ng_tin` | Nigerian Tax Identification Number | | Norway | `no_vat` - /// | Norwegian VAT Number | | Norway | `no_voec` | Norwegian - /// VAT on e-commerce Number | | Oman | `om_vat` | Omani VAT Number - /// | | Peru | `pe_ruc` | Peruvian RUC Number - /// | | Philippines | `ph_tin ` | Philippines Tax Identification - /// Number | | Poland | `eu_vat` | European VAT Number - /// | | Portugal | `eu_vat` | European VAT Number | | - /// Romania | `eu_vat` | European VAT Number | | Romania - /// | `ro_tin` | Romanian Tax ID Number | | Russia - /// | `ru_inn` | Russian INN | | Russia | `ru_kpp` - /// | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi - /// Arabia VAT | | Serbia | `rs_pib` | Serbian PIB - /// Number | | Singapore | `sg_gst` | Singaporean GST - /// | | Singapore | `sg_uen` | Singaporean UEN - /// | | Slovakia | `eu_vat` | European VAT Number - /// | | Slovenia | `eu_vat` | European VAT Number - /// | | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) - /// | | South Africa | `za_vat` | South African VAT - /// Number | | South Korea | `kr_brn` | Korean - /// BRN | | Spain | `es_cif` - /// | Spanish NIF Number (previously Spanish CIF Number) | | Spain - /// | `eu_vat` | European VAT Number | | - /// Sweden | `eu_vat` | European VAT Number - /// | | Switzerland | `ch_vat` | Switzerland VAT Number - /// | | Taiwan | `tw_vat` | Taiwanese VAT - /// | | Thailand | `th_vat` | - /// Thai VAT | | Turkey - /// | `tr_tin` | Turkish Tax Identification Number | | Ukraine - /// | `ua_vat` | Ukrainian VAT - /// | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN - /// | | United Kingdom | `eu_vat` | Northern Ireland - /// VAT Number | | United Kingdom | `gb_vat` | United - /// Kingdom VAT Number | | United States | `us_ein` - /// | United States EIN | | Uruguay - /// | `uy_ruc` | Uruguayan RUC Number | | Venezuela - /// | `ve_rif` | Venezuelan RIF Number - /// | | Vietnam | `vn_tin` | Vietnamese Tax ID Number - /// | + /// + /// + /// var result = instance.Match( + /// (NewAvalaraTaxConfiguration value) => {...}, + /// (NewTaxJarConfiguration value) => {...}, + /// (NewSphereConfiguration value) => {...}, + /// (CustomerUpdateParamsTaxConfigurationNumeral value) => {...}, + /// (CustomerUpdateParamsTaxConfigurationAnrok value) => {...}, + /// (CustomerUpdateParamsTaxConfigurationStripe value) => {...} + /// ); + /// + /// /// - public Models::CustomerTaxID? TaxID + public T Match( + System::Func newAvalara, + System::Func newTaxJar, + System::Func newSphere, + System::Func numeral, + System::Func anrok, + System::Func stripe + ) { - get + return this.Value switch + { + NewAvalaraTaxConfiguration value => newAvalara(value), + NewTaxJarConfiguration value => newTaxJar(value), + NewSphereConfiguration value => newSphere(value), + CustomerUpdateParamsTaxConfigurationNumeral value => numeral(value), + CustomerUpdateParamsTaxConfigurationAnrok value => anrok(value), + CustomerUpdateParamsTaxConfigurationStripe value => stripe(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CustomerUpdateParamsTaxConfiguration" + ), + }; + } + + public static implicit operator CustomerUpdateParamsTaxConfiguration( + NewAvalaraTaxConfiguration value + ) => new(value); + + public static implicit operator CustomerUpdateParamsTaxConfiguration( + NewTaxJarConfiguration value + ) => new(value); + + public static implicit operator CustomerUpdateParamsTaxConfiguration( + NewSphereConfiguration value + ) => new(value); + + public static implicit operator CustomerUpdateParamsTaxConfiguration( + CustomerUpdateParamsTaxConfigurationNumeral value + ) => new(value); + + public static implicit operator CustomerUpdateParamsTaxConfiguration( + CustomerUpdateParamsTaxConfigurationAnrok value + ) => new(value); + + public static implicit operator CustomerUpdateParamsTaxConfiguration( + CustomerUpdateParamsTaxConfigurationStripe value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) { - if (!this.BodyProperties.TryGetValue("tax_id", out Json::JsonElement element)) - return null; + throw new OrbInvalidDataException( + "Data did not match any variant of CustomerUpdateParamsTaxConfiguration" + ); + } + this.Switch( + (newAvalara) => newAvalara.Validate(), + (newTaxJar) => newTaxJar.Validate(), + (newSphere) => newSphere.Validate(), + (numeral) => numeral.Validate(), + (anrok) => anrok.Validate(), + (stripe) => stripe.Validate() + ); + } + + public virtual bool Equals(CustomerUpdateParamsTaxConfiguration? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CustomerUpdateParamsTaxConfigurationConverter + : JsonConverter +{ + public override CustomerUpdateParamsTaxConfiguration? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? taxProvider; + try + { + taxProvider = element.GetProperty("tax_provider").GetString(); + } + catch + { + taxProvider = null; + } + + switch (taxProvider) + { + case "avalara": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "taxjar": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } - return Json::JsonSerializer.Deserialize(element); + return new(element); + } + case "sphere": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "numeral": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "anrok": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "stripe": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new CustomerUpdateParamsTaxConfiguration(element); + } } - set { this.BodyProperties["tax_id"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public override void Write( + Utf8JsonWriter writer, + CustomerUpdateParamsTaxConfiguration? value, + JsonSerializerOptions options + ) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') - + string.Format("/customers/{0}", this.CustomerID) + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateParamsTaxConfigurationNumeral, + CustomerUpdateParamsTaxConfigurationNumeralFromRaw + >) +)] +public sealed record class CustomerUpdateParamsTaxConfigurationNumeral : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"numeral\"") + ) ) { - Query = this.QueryString(client), - }.Uri; + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.AutomaticTaxEnabled; } - public Http::StringContent BodyContent() + public CustomerUpdateParamsTaxConfigurationNumeral() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this.TaxProvider = JsonSerializer.Deserialize("\"numeral\""); + } + + public CustomerUpdateParamsTaxConfigurationNumeral( + CustomerUpdateParamsTaxConfigurationNumeral customerUpdateParamsTaxConfigurationNumeral + ) + : base(customerUpdateParamsTaxConfigurationNumeral) { } + + public CustomerUpdateParamsTaxConfigurationNumeral( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"numeral\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateParamsTaxConfigurationNumeral(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateParamsTaxConfigurationNumeral FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateParamsTaxConfigurationNumeral(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; + } +} + +class CustomerUpdateParamsTaxConfigurationNumeralFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateParamsTaxConfigurationNumeral FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateParamsTaxConfigurationNumeral.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateParamsTaxConfigurationAnrok, + CustomerUpdateParamsTaxConfigurationAnrokFromRaw + >) +)] +public sealed record class CustomerUpdateParamsTaxConfigurationAnrok : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"anrok\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.AutomaticTaxEnabled; + } + + public CustomerUpdateParamsTaxConfigurationAnrok() + { + this.TaxProvider = JsonSerializer.Deserialize("\"anrok\""); + } + + public CustomerUpdateParamsTaxConfigurationAnrok( + CustomerUpdateParamsTaxConfigurationAnrok customerUpdateParamsTaxConfigurationAnrok + ) + : base(customerUpdateParamsTaxConfigurationAnrok) { } + + public CustomerUpdateParamsTaxConfigurationAnrok( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"anrok\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateParamsTaxConfigurationAnrok(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateParamsTaxConfigurationAnrok FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateParamsTaxConfigurationAnrok(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; + } +} + +class CustomerUpdateParamsTaxConfigurationAnrokFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateParamsTaxConfigurationAnrok FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateParamsTaxConfigurationAnrok.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + CustomerUpdateParamsTaxConfigurationStripe, + CustomerUpdateParamsTaxConfigurationStripeFromRaw + >) +)] +public sealed record class CustomerUpdateParamsTaxConfigurationStripe : JsonModel +{ + public required bool TaxExempt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } + } + + public JsonElement TaxProvider + { + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_provider"); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } + + /// + public override void Validate() + { + _ = this.TaxExempt; + if ( + !JsonElement.DeepEquals( + this.TaxProvider, + JsonSerializer.Deserialize("\"stripe\"") + ) + ) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + throw new OrbInvalidDataException("Invalid value given for constant"); } + _ = this.AutomaticTaxEnabled; + } + + public CustomerUpdateParamsTaxConfigurationStripe() + { + this.TaxProvider = JsonSerializer.Deserialize("\"stripe\""); + } + + public CustomerUpdateParamsTaxConfigurationStripe( + CustomerUpdateParamsTaxConfigurationStripe customerUpdateParamsTaxConfigurationStripe + ) + : base(customerUpdateParamsTaxConfigurationStripe) { } + + public CustomerUpdateParamsTaxConfigurationStripe( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.TaxProvider = JsonSerializer.Deserialize("\"stripe\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerUpdateParamsTaxConfigurationStripe(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CustomerUpdateParamsTaxConfigurationStripe FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public CustomerUpdateParamsTaxConfigurationStripe(bool taxExempt) + : this() + { + this.TaxExempt = taxExempt; } } + +class CustomerUpdateParamsTaxConfigurationStripeFromRaw + : IFromRawJson +{ + /// + public CustomerUpdateParamsTaxConfigurationStripe FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CustomerUpdateParamsTaxConfigurationStripe.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/CustomerUpdateParamsProperties/PaymentProvider.cs b/src/Orb/Models/Customers/CustomerUpdateParamsProperties/PaymentProvider.cs deleted file mode 100644 index 5654a639..00000000 --- a/src/Orb/Models/Customers/CustomerUpdateParamsProperties/PaymentProvider.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.CustomerUpdateParamsProperties; - -/// -/// This is used for creating charges or invoices in an external system via Orb. When -/// not in test mode: - the connection must first be configured in the Orb webapp. -/// - if the provider is an invoicing provider (`stripe_invoice`, `quickbooks`, `bill.com`, -/// `netsuite`), any product mappings must first be configured with the Orb team. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PaymentProvider(string value) : Orb::IEnum -{ - public static readonly PaymentProvider Quickbooks = new("quickbooks"); - - public static readonly PaymentProvider BillCom = new("bill.com"); - - public static readonly PaymentProvider StripeCharge = new("stripe_charge"); - - public static readonly PaymentProvider StripeInvoice = new("stripe_invoice"); - - public static readonly PaymentProvider Netsuite = new("netsuite"); - - readonly string _value = value; - - public enum Value - { - Quickbooks, - BillCom, - StripeCharge, - StripeInvoice, - Netsuite, - } - - public Value Known() => - _value switch - { - "quickbooks" => Value.Quickbooks, - "bill.com" => Value.BillCom, - "stripe_charge" => Value.StripeCharge, - "stripe_invoice" => Value.StripeInvoice, - "netsuite" => Value.Netsuite, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PaymentProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/CustomerUpdateParamsProperties/TaxConfiguration.cs b/src/Orb/Models/Customers/CustomerUpdateParamsProperties/TaxConfiguration.cs deleted file mode 100644 index 338cf86e..00000000 --- a/src/Orb/Models/Customers/CustomerUpdateParamsProperties/TaxConfiguration.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Customers = Orb.Models.Customers; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TaxConfigurationVariants = Orb.Models.Customers.CustomerUpdateParamsProperties.TaxConfigurationVariants; - -namespace Orb.Models.Customers.CustomerUpdateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class TaxConfiguration -{ - internal TaxConfiguration() { } - - public static TaxConfigurationVariants::NewAvalaraTaxConfiguration Create( - Customers::NewAvalaraTaxConfiguration value - ) => new(value); - - public static TaxConfigurationVariants::NewTaxJarConfiguration Create( - Customers::NewTaxJarConfiguration value - ) => new(value); - - public static TaxConfigurationVariants::NewSphereConfiguration Create( - Customers::NewSphereConfiguration value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Customers/CustomerUpdateParamsProperties/TaxConfigurationVariants/All.cs b/src/Orb/Models/Customers/CustomerUpdateParamsProperties/TaxConfigurationVariants/All.cs deleted file mode 100644 index 21935bd2..00000000 --- a/src/Orb/Models/Customers/CustomerUpdateParamsProperties/TaxConfigurationVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Customers = Orb.Models.Customers; -using CustomerUpdateParamsProperties = Orb.Models.Customers.CustomerUpdateParamsProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Customers.CustomerUpdateParamsProperties.TaxConfigurationVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAvalaraTaxConfiguration(Customers::NewAvalaraTaxConfiguration Value) - : CustomerUpdateParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewAvalaraTaxConfiguration From(Customers::NewAvalaraTaxConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewTaxJarConfiguration(Customers::NewTaxJarConfiguration Value) - : CustomerUpdateParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewTaxJarConfiguration From(Customers::NewTaxJarConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSphereConfiguration(Customers::NewSphereConfiguration Value) - : CustomerUpdateParamsProperties::TaxConfiguration, - Orb::IVariant -{ - public static NewSphereConfiguration From(Customers::NewSphereConfiguration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Customers/NewAccountingSyncConfiguration.cs b/src/Orb/Models/Customers/NewAccountingSyncConfiguration.cs index 75706a9e..7c73c384 100644 --- a/src/Orb/Models/Customers/NewAccountingSyncConfiguration.cs +++ b/src/Orb/Models/Customers/NewAccountingSyncConfiguration.cs @@ -1,47 +1,39 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewAccountingSyncConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewAccountingSyncConfiguration, + NewAccountingSyncConfigurationFromRaw + >) +)] +public sealed record class NewAccountingSyncConfiguration : JsonModel { - public Generic::List? AccountingProviders + public IReadOnlyList? AccountingProviders { get { - if (!this.Properties.TryGetValue("accounting_providers", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.Properties["accounting_providers"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawData, + "accounting_providers" ); } + init { JsonModel.Set(this._rawData, "accounting_providers", value); } } public bool? Excluded { - get - { - if (!this.Properties.TryGetValue("excluded", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["excluded"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "excluded"); } + init { JsonModel.Set(this._rawData, "excluded", value); } } + /// public override void Validate() { foreach (var item in this.AccountingProviders ?? []) @@ -53,18 +45,37 @@ public override void Validate() public NewAccountingSyncConfiguration() { } + public NewAccountingSyncConfiguration( + NewAccountingSyncConfiguration newAccountingSyncConfiguration + ) + : base(newAccountingSyncConfiguration) { } + + public NewAccountingSyncConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewAccountingSyncConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewAccountingSyncConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewAccountingSyncConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class NewAccountingSyncConfigurationFromRaw : IFromRawJson +{ + /// + public NewAccountingSyncConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewAccountingSyncConfiguration.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/NewAvalaraTaxConfiguration.cs b/src/Orb/Models/Customers/NewAvalaraTaxConfiguration.cs index 98cbc46f..983d2f6b 100644 --- a/src/Orb/Models/Customers/NewAvalaraTaxConfiguration.cs +++ b/src/Orb/Models/Customers/NewAvalaraTaxConfiguration.cs @@ -1,86 +1,134 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewAvalaraTaxConfigurationProperties = Orb.Models.Customers.NewAvalaraTaxConfigurationProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewAvalaraTaxConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewAvalaraTaxConfiguration : JsonModel { public required bool TaxExempt { - get - { - if (!this.Properties.TryGetValue("tax_exempt", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_exempt", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["tax_exempt"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } } - public required NewAvalaraTaxConfigurationProperties::TaxProvider TaxProvider + public required ApiEnum TaxProvider { get { - if (!this.Properties.TryGetValue("tax_provider", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_provider", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("tax_provider"); + return JsonModel.GetNotNullClass>( + this.RawData, + "tax_provider" + ); } - set { this.Properties["tax_provider"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } } - public string? TaxExemptionCode + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled { - get - { - if (!this.Properties.TryGetValue("tax_exemption_code", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["tax_exemption_code"] = Json::JsonSerializer.SerializeToElement(value); - } + public string? TaxExemptionCode + { + get { return JsonModel.GetNullableClass(this.RawData, "tax_exemption_code"); } + init { JsonModel.Set(this._rawData, "tax_exemption_code", value); } } + /// public override void Validate() { _ = this.TaxExempt; this.TaxProvider.Validate(); + _ = this.AutomaticTaxEnabled; _ = this.TaxExemptionCode; } public NewAvalaraTaxConfiguration() { } + public NewAvalaraTaxConfiguration(NewAvalaraTaxConfiguration newAvalaraTaxConfiguration) + : base(newAvalaraTaxConfiguration) { } + + public NewAvalaraTaxConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewAvalaraTaxConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewAvalaraTaxConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewAvalaraTaxConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewAvalaraTaxConfigurationFromRaw : IFromRawJson +{ + /// + public NewAvalaraTaxConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewAvalaraTaxConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TaxProviderConverter))] +public enum TaxProvider +{ + Avalara, +} + +sealed class TaxProviderConverter : JsonConverter +{ + public override TaxProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "avalara" => TaxProvider.Avalara, + _ => (TaxProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TaxProvider value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + TaxProvider.Avalara => "avalara", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/NewAvalaraTaxConfigurationProperties/TaxProvider.cs b/src/Orb/Models/Customers/NewAvalaraTaxConfigurationProperties/TaxProvider.cs deleted file mode 100644 index 413280ba..00000000 --- a/src/Orb/Models/Customers/NewAvalaraTaxConfigurationProperties/TaxProvider.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.NewAvalaraTaxConfigurationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class TaxProvider(string value) : Orb::IEnum -{ - public static readonly TaxProvider Avalara = new("avalara"); - - readonly string _value = value; - - public enum Value - { - Avalara, - } - - public Value Known() => - _value switch - { - "avalara" => Value.Avalara, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static TaxProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/NewReportingConfiguration.cs b/src/Orb/Models/Customers/NewReportingConfiguration.cs index 03b51715..bdc56e21 100644 --- a/src/Orb/Models/Customers/NewReportingConfiguration.cs +++ b/src/Orb/Models/Customers/NewReportingConfiguration.cs @@ -1,32 +1,24 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewReportingConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewReportingConfiguration : JsonModel { public required bool Exempt { - get - { - if (!this.Properties.TryGetValue("exempt", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "exempt", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["exempt"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "exempt"); } + init { JsonModel.Set(this._rawData, "exempt", value); } } + /// public override void Validate() { _ = this.Exempt; @@ -34,18 +26,42 @@ public override void Validate() public NewReportingConfiguration() { } + public NewReportingConfiguration(NewReportingConfiguration newReportingConfiguration) + : base(newReportingConfiguration) { } + + public NewReportingConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewReportingConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewReportingConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewReportingConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewReportingConfiguration(bool exempt) + : this() + { + this.Exempt = exempt; } } + +class NewReportingConfigurationFromRaw : IFromRawJson +{ + /// + public NewReportingConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewReportingConfiguration.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Customers/NewSphereConfiguration.cs b/src/Orb/Models/Customers/NewSphereConfiguration.cs index 57a40c58..2850f604 100644 --- a/src/Orb/Models/Customers/NewSphereConfiguration.cs +++ b/src/Orb/Models/Customers/NewSphereConfiguration.cs @@ -1,70 +1,126 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewSphereConfigurationProperties = Orb.Models.Customers.NewSphereConfigurationProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSphereConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewSphereConfiguration : JsonModel { public required bool TaxExempt { - get - { - if (!this.Properties.TryGetValue("tax_exempt", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_exempt", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["tax_exempt"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } } - public required NewSphereConfigurationProperties::TaxProvider TaxProvider + public required ApiEnum TaxProvider { get { - if (!this.Properties.TryGetValue("tax_provider", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_provider", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("tax_provider"); + return JsonModel.GetNotNullClass>( + this.RawData, + "tax_provider" + ); } - set { this.Properties["tax_provider"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } } + /// public override void Validate() { _ = this.TaxExempt; this.TaxProvider.Validate(); + _ = this.AutomaticTaxEnabled; } public NewSphereConfiguration() { } + public NewSphereConfiguration(NewSphereConfiguration newSphereConfiguration) + : base(newSphereConfiguration) { } + + public NewSphereConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSphereConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSphereConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSphereConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSphereConfigurationFromRaw : IFromRawJson +{ + /// + public NewSphereConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSphereConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSphereConfigurationTaxProviderConverter))] +public enum NewSphereConfigurationTaxProvider +{ + Sphere, +} + +sealed class NewSphereConfigurationTaxProviderConverter + : JsonConverter +{ + public override NewSphereConfigurationTaxProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "sphere" => NewSphereConfigurationTaxProvider.Sphere, + _ => (NewSphereConfigurationTaxProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSphereConfigurationTaxProvider value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewSphereConfigurationTaxProvider.Sphere => "sphere", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/NewSphereConfigurationProperties/TaxProvider.cs b/src/Orb/Models/Customers/NewSphereConfigurationProperties/TaxProvider.cs deleted file mode 100644 index 2d505002..00000000 --- a/src/Orb/Models/Customers/NewSphereConfigurationProperties/TaxProvider.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.NewSphereConfigurationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class TaxProvider(string value) : Orb::IEnum -{ - public static readonly TaxProvider Sphere = new("sphere"); - - readonly string _value = value; - - public enum Value - { - Sphere, - } - - public Value Known() => - _value switch - { - "sphere" => Value.Sphere, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static TaxProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Customers/NewTaxJarConfiguration.cs b/src/Orb/Models/Customers/NewTaxJarConfiguration.cs index 9aa7340e..25685dc0 100644 --- a/src/Orb/Models/Customers/NewTaxJarConfiguration.cs +++ b/src/Orb/Models/Customers/NewTaxJarConfiguration.cs @@ -1,70 +1,126 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewTaxJarConfigurationProperties = Orb.Models.Customers.NewTaxJarConfigurationProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Customers; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewTaxJarConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewTaxJarConfiguration : JsonModel { public required bool TaxExempt { - get - { - if (!this.Properties.TryGetValue("tax_exempt", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_exempt", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["tax_exempt"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "tax_exempt"); } + init { JsonModel.Set(this._rawData, "tax_exempt", value); } } - public required NewTaxJarConfigurationProperties::TaxProvider TaxProvider + public required ApiEnum TaxProvider { get { - if (!this.Properties.TryGetValue("tax_provider", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_provider", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("tax_provider"); + return JsonModel.GetNotNullClass>( + this.RawData, + "tax_provider" + ); } - set { this.Properties["tax_provider"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "tax_provider", value); } + } + + /// + /// Whether to automatically calculate tax for this customer. When null, inherits + /// from account-level setting. When true or false, overrides the account setting. + /// + public bool? AutomaticTaxEnabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "automatic_tax_enabled"); } + init { JsonModel.Set(this._rawData, "automatic_tax_enabled", value); } } + /// public override void Validate() { _ = this.TaxExempt; this.TaxProvider.Validate(); + _ = this.AutomaticTaxEnabled; } public NewTaxJarConfiguration() { } + public NewTaxJarConfiguration(NewTaxJarConfiguration newTaxJarConfiguration) + : base(newTaxJarConfiguration) { } + + public NewTaxJarConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewTaxJarConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewTaxJarConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewTaxJarConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewTaxJarConfigurationFromRaw : IFromRawJson +{ + /// + public NewTaxJarConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewTaxJarConfiguration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewTaxJarConfigurationTaxProviderConverter))] +public enum NewTaxJarConfigurationTaxProvider +{ + Taxjar, +} + +sealed class NewTaxJarConfigurationTaxProviderConverter + : JsonConverter +{ + public override NewTaxJarConfigurationTaxProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "taxjar" => NewTaxJarConfigurationTaxProvider.Taxjar, + _ => (NewTaxJarConfigurationTaxProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewTaxJarConfigurationTaxProvider value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewTaxJarConfigurationTaxProvider.Taxjar => "taxjar", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Customers/NewTaxJarConfigurationProperties/TaxProvider.cs b/src/Orb/Models/Customers/NewTaxJarConfigurationProperties/TaxProvider.cs deleted file mode 100644 index 650a4322..00000000 --- a/src/Orb/Models/Customers/NewTaxJarConfigurationProperties/TaxProvider.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Customers.NewTaxJarConfigurationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class TaxProvider(string value) : Orb::IEnum -{ - public static readonly TaxProvider Taxjar = new("taxjar"); - - readonly string _value = value; - - public enum Value - { - Taxjar, - } - - public Value Known() => - _value switch - { - "taxjar" => Value.Taxjar, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static TaxProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/DimensionalPriceConfiguration.cs b/src/Orb/Models/DimensionalPriceConfiguration.cs index 4a979e69..73dbf1c6 100644 --- a/src/Orb/Models/DimensionalPriceConfiguration.cs +++ b/src/Orb/Models/DimensionalPriceConfiguration.cs @@ -1,85 +1,72 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class DimensionalPriceConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class DimensionalPriceConfiguration : JsonModel { - public required Generic::List DimensionValues + public required IReadOnlyList DimensionValues { - get - { - if (!this.Properties.TryGetValue("dimension_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimension_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimension_values"); - } - set - { - this.Properties["dimension_values"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimension_values"); } + init { JsonModel.Set(this._rawData, "dimension_values", value); } } public required string DimensionalPriceGroupID { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_group_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "dimensional_price_group_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("dimensional_price_group_id"); - } - set - { - this.Properties["dimensional_price_group_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass(this.RawData, "dimensional_price_group_id"); } + init { JsonModel.Set(this._rawData, "dimensional_price_group_id", value); } } + /// public override void Validate() { - foreach (var item in this.DimensionValues) - { - _ = item; - } + _ = this.DimensionValues; _ = this.DimensionalPriceGroupID; } public DimensionalPriceConfiguration() { } + public DimensionalPriceConfiguration( + DimensionalPriceConfiguration dimensionalPriceConfiguration + ) + : base(dimensionalPriceConfiguration) { } + + public DimensionalPriceConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - DimensionalPriceConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + DimensionalPriceConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static DimensionalPriceConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class DimensionalPriceConfigurationFromRaw : IFromRawJson +{ + /// + public DimensionalPriceConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => DimensionalPriceConfiguration.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroup.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroup.cs index 08d56e9f..b3d51680 100644 --- a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroup.cs +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroup.cs @@ -1,9 +1,9 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.DimensionalPriceGroups; @@ -12,64 +12,33 @@ namespace Orb.Models.DimensionalPriceGroups; /// by a set of dimensions. Prices in a price group must specify the parition used /// to derive their usage. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class DimensionalPriceGroup - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class DimensionalPriceGroup : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// The billable metric associated with this dimensional price group. All prices - /// associated with this dimensional price group will be computed using this billable metric. + /// associated with this dimensional price group will be computed using this + /// billable metric. /// public required string BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billable_metric_id"); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// /// The dimensions that this dimensional price group is defined over /// - public required Generic::List Dimensions + public required IReadOnlyList Dimensions { - get - { - if (!this.Properties.TryGetValue("dimensions", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimensions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimensions"); - } - set { this.Properties["dimensions"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimensions"); } + init { JsonModel.Set(this._rawData, "dimensions", value); } } /// @@ -79,24 +48,12 @@ public required string? ExternalDimensionalPriceGroupID { get { - if ( - !this.Properties.TryGetValue( - "external_dimensional_price_group_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "external_dimensional_price_group_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_dimensional_price_group_id"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "external_dimensional_price_group_id" + ); } + init { JsonModel.Set(this._rawData, "external_dimensional_price_group_id", value); } } /// @@ -105,20 +62,13 @@ public required string? ExternalDimensionalPriceGroupID /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -126,47 +76,52 @@ public required string? ExternalDimensionalPriceGroupID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// public override void Validate() { _ = this.ID; _ = this.BillableMetricID; - foreach (var item in this.Dimensions) - { - _ = item; - } + _ = this.Dimensions; _ = this.ExternalDimensionalPriceGroupID; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.Name; } public DimensionalPriceGroup() { } + public DimensionalPriceGroup(DimensionalPriceGroup dimensionalPriceGroup) + : base(dimensionalPriceGroup) { } + + public DimensionalPriceGroup(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - DimensionalPriceGroup(Generic::Dictionary properties) + [SetsRequiredMembers] + DimensionalPriceGroup(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static DimensionalPriceGroup FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class DimensionalPriceGroupFromRaw : IFromRawJson +{ + /// + public DimensionalPriceGroup FromRawUnchecked( + IReadOnlyDictionary rawData + ) => DimensionalPriceGroup.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParams.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParams.cs index 8a5c2768..ac9a34de 100644 --- a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParams.cs +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupCreateParams.cs @@ -1,103 +1,63 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.DimensionalPriceGroups; /// /// A dimensional price group is used to partition the result of a billable metric -/// by a set of dimensions. Prices in a price group must specify the parition used +/// by a set of dimensions. Prices in a price group must specify the partition used /// to derive their usage. /// -/// For example, suppose we have a billable metric that measures the number of widgets -/// used and we want to charge differently depending on the color of the widget. We -/// can create a price group with a dimension "color" and two prices: one that charges -/// \$10 per red widget and one that charges \$20 per blue widget. +/// For example, suppose we have a billable metric that measures the number +/// of widgets used and we want to charge differently depending on the color of the +/// widget. We can create a price group with a dimension "color" and two prices: one +/// that charges \$10 per red widget and one that charges \$20 per blue widget. /// -public sealed record class DimensionalPriceGroupCreateParams : Orb::ParamsBase +public sealed record class DimensionalPriceGroupCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } public required string BillableMetricID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "billable_metric_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billable_metric_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billable_metric_id"); - } - set - { - this.BodyProperties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "billable_metric_id"); } + init { JsonModel.Set(this._rawBodyData, "billable_metric_id", value); } } /// /// The set of keys (in order) used to disambiguate prices in the group. /// - public required Generic::List Dimensions + public required IReadOnlyList Dimensions { - get - { - if (!this.BodyProperties.TryGetValue("dimensions", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimensions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimensions"); - } - set { this.BodyProperties["dimensions"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawBodyData, "dimensions"); } + init { JsonModel.Set(this._rawBodyData, "dimensions", value); } } public required string Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } } public string? ExternalDimensionalPriceGroupID { get { - if ( - !this.BodyProperties.TryGetValue( - "external_dimensional_price_group_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_dimensional_price_group_id"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawBodyData, + "external_dimensional_price_group_id" + ); } + init { JsonModel.Set(this._rawBodyData, "external_dimensional_price_group_id", value); } } /// @@ -105,43 +65,90 @@ public string? ExternalDimensionalPriceGroupID /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public DimensionalPriceGroupCreateParams() { } + + public DimensionalPriceGroupCreateParams( + DimensionalPriceGroupCreateParams dimensionalPriceGroupCreateParams + ) + : base(dimensionalPriceGroupCreateParams) + { + this._rawBodyData = [.. dimensionalPriceGroupCreateParams._rawBodyData]; + } + + public DimensionalPriceGroupCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionalPriceGroupCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static DimensionalPriceGroupCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + "/dimensional_price_groups" - ) + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/dimensional_price_groups") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupDimensionalPriceGroups.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupDimensionalPriceGroups.cs new file mode 100644 index 00000000..4e75b513 --- /dev/null +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupDimensionalPriceGroups.cs @@ -0,0 +1,84 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; + +namespace Orb.Models.DimensionalPriceGroups; + +[JsonConverter( + typeof(JsonModelConverter< + DimensionalPriceGroupDimensionalPriceGroups, + DimensionalPriceGroupDimensionalPriceGroupsFromRaw + >) +)] +public sealed record class DimensionalPriceGroupDimensionalPriceGroups : JsonModel +{ + public required IReadOnlyList Data + { + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } + } + + public required PaginationMetadata PaginationMetadata + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); + } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Data) + { + item.Validate(); + } + this.PaginationMetadata.Validate(); + } + + public DimensionalPriceGroupDimensionalPriceGroups() { } + + public DimensionalPriceGroupDimensionalPriceGroups( + DimensionalPriceGroupDimensionalPriceGroups dimensionalPriceGroupDimensionalPriceGroups + ) + : base(dimensionalPriceGroupDimensionalPriceGroups) { } + + public DimensionalPriceGroupDimensionalPriceGroups( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionalPriceGroupDimensionalPriceGroups(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static DimensionalPriceGroupDimensionalPriceGroups FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DimensionalPriceGroupDimensionalPriceGroupsFromRaw + : IFromRawJson +{ + /// + public DimensionalPriceGroupDimensionalPriceGroups FromRawUnchecked( + IReadOnlyDictionary rawData + ) => DimensionalPriceGroupDimensionalPriceGroups.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListPage.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListPage.cs new file mode 100644 index 00000000..a7c55951 --- /dev/null +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListPage.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.DimensionalPriceGroups; + +public sealed class DimensionalPriceGroupListPage( + IDimensionalPriceGroupService service, + DimensionalPriceGroupListParams parameters, + DimensionalPriceGroupDimensionalPriceGroups response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next( + CancellationToken cancellationToken = default + ) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListParams.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListParams.cs index 985669e6..cb7a7828 100644 --- a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListParams.cs +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupListParams.cs @@ -1,14 +1,17 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.DimensionalPriceGroups; /// /// List dimensional price groups /// -public sealed record class DimensionalPriceGroupListParams : Orb::ParamsBase +public sealed record class DimensionalPriceGroupListParams : ParamsBase { /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -16,14 +19,8 @@ public sealed record class DimensionalPriceGroupListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -31,32 +28,72 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public DimensionalPriceGroupListParams() { } + + public DimensionalPriceGroupListParams( + DimensionalPriceGroupListParams dimensionalPriceGroupListParams + ) + : base(dimensionalPriceGroupListParams) { } + + public DimensionalPriceGroupListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionalPriceGroupListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static DimensionalPriceGroupListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + "/dimensional_price_groups" - ) + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/dimensional_price_groups") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParams.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParams.cs index a0fbb959..fca8b9ad 100644 --- a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParams.cs +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupRetrieveParams.cs @@ -1,33 +1,77 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.DimensionalPriceGroups; /// /// Fetch dimensional price group /// -public sealed record class DimensionalPriceGroupRetrieveParams : Orb::ParamsBase +public sealed record class DimensionalPriceGroupRetrieveParams : ParamsBase { - public required string DimensionalPriceGroupID; + public string? DimensionalPriceGroupID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public DimensionalPriceGroupRetrieveParams() { } + + public DimensionalPriceGroupRetrieveParams( + DimensionalPriceGroupRetrieveParams dimensionalPriceGroupRetrieveParams + ) + : base(dimensionalPriceGroupRetrieveParams) { } + + public DimensionalPriceGroupRetrieveParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionalPriceGroupRetrieveParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static DimensionalPriceGroupRetrieveParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/dimensional_price_groups/{0}", this.DimensionalPriceGroupID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupUpdateParams.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupUpdateParams.cs new file mode 100644 index 00000000..1d1e3373 --- /dev/null +++ b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroupUpdateParams.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; + +namespace Orb.Models.DimensionalPriceGroups; + +/// +/// This endpoint can be used to update the `external_dimensional_price_group_id` +/// and `metadata` of an existing dimensional price group. Other fields on a dimensional +/// price group are currently immutable. +/// +public sealed record class DimensionalPriceGroupUpdateParams : ParamsBase +{ + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } + + public string? DimensionalPriceGroupID { get; init; } + + /// + /// An optional user-defined ID for this dimensional price group resource, used + /// throughout the system as an alias for this dimensional price group. Use this + /// field to identify a dimensional price group by an existing identifier in + /// your system. + /// + public string? ExternalDimensionalPriceGroupID + { + get + { + return JsonModel.GetNullableClass( + this.RawBodyData, + "external_dimensional_price_group_id" + ); + } + init { JsonModel.Set(this._rawBodyData, "external_dimensional_price_group_id", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); + } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public DimensionalPriceGroupUpdateParams() { } + + public DimensionalPriceGroupUpdateParams( + DimensionalPriceGroupUpdateParams dimensionalPriceGroupUpdateParams + ) + : base(dimensionalPriceGroupUpdateParams) + { + this._rawBodyData = [.. dimensionalPriceGroupUpdateParams._rawBodyData]; + } + + public DimensionalPriceGroupUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionalPriceGroupUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static DimensionalPriceGroupUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override Uri Url(ClientOptions options) + { + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format("/dimensional_price_groups/{0}", this.DimensionalPriceGroupID) + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} diff --git a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroups.cs b/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroups.cs deleted file mode 100644 index fbd94dbe..00000000 --- a/src/Orb/Models/DimensionalPriceGroups/DimensionalPriceGroups.cs +++ /dev/null @@ -1,73 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.DimensionalPriceGroups; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class DimensionalPriceGroups - : Orb::ModelBase, - Orb::IFromRaw -{ - public required Generic::List Data - { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::PaginationMetadata PaginationMetadata - { - get - { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - foreach (var item in this.Data) - { - item.Validate(); - } - this.PaginationMetadata.Validate(); - } - - public DimensionalPriceGroups() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - DimensionalPriceGroups(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static DimensionalPriceGroups FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParams.cs b/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParams.cs index e1cb6200..012cbab3 100644 --- a/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParams.cs +++ b/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDRetrieveParams.cs @@ -1,36 +1,80 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; /// /// Fetch dimensional price group by external ID /// -public sealed record class ExternalDimensionalPriceGroupIDRetrieveParams : Orb::ParamsBase +public sealed record class ExternalDimensionalPriceGroupIDRetrieveParams : ParamsBase { - public required string ExternalDimensionalPriceGroupID; + public string? ExternalDimensionalPriceGroupID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public ExternalDimensionalPriceGroupIDRetrieveParams() { } + + public ExternalDimensionalPriceGroupIDRetrieveParams( + ExternalDimensionalPriceGroupIDRetrieveParams externalDimensionalPriceGroupIDRetrieveParams + ) + : base(externalDimensionalPriceGroupIDRetrieveParams) { } + + public ExternalDimensionalPriceGroupIDRetrieveParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalDimensionalPriceGroupIDRetrieveParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalDimensionalPriceGroupIDRetrieveParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/dimensional_price_groups/external_dimensional_price_group_id/{0}", this.ExternalDimensionalPriceGroupID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDUpdateParams.cs b/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDUpdateParams.cs new file mode 100644 index 00000000..5843b3d6 --- /dev/null +++ b/src/Orb/Models/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDUpdateParams.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; + +namespace Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +/// +/// This endpoint can be used to update the `external_dimensional_price_group_id` +/// and `metadata` of an existing dimensional price group. Other fields on a dimensional +/// price group are currently immutable. +/// +public sealed record class ExternalDimensionalPriceGroupIDUpdateParams : ParamsBase +{ + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } + + public string? ExternalDimensionalPriceGroupID { get; init; } + + /// + /// An optional user-defined ID for this dimensional price group resource, used + /// throughout the system as an alias for this dimensional price group. Use this + /// field to identify a dimensional price group by an existing identifier in + /// your system. + /// + public string? ExternalDimensionalPriceGroupIDValue + { + get + { + return JsonModel.GetNullableClass( + this.RawBodyData, + "external_dimensional_price_group_id" + ); + } + init { JsonModel.Set(this._rawBodyData, "external_dimensional_price_group_id", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); + } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public ExternalDimensionalPriceGroupIDUpdateParams() { } + + public ExternalDimensionalPriceGroupIDUpdateParams( + ExternalDimensionalPriceGroupIDUpdateParams externalDimensionalPriceGroupIDUpdateParams + ) + : base(externalDimensionalPriceGroupIDUpdateParams) + { + this._rawBodyData = [.. externalDimensionalPriceGroupIDUpdateParams._rawBodyData]; + } + + public ExternalDimensionalPriceGroupIDUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalDimensionalPriceGroupIDUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalDimensionalPriceGroupIDUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override Uri Url(ClientOptions options) + { + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format( + "/dimensional_price_groups/external_dimensional_price_group_id/{0}", + this.ExternalDimensionalPriceGroupID + ) + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} diff --git a/src/Orb/Models/Discount.cs b/src/Orb/Models/Discount.cs deleted file mode 100644 index 92b0dd33..00000000 --- a/src/Orb/Models/Discount.cs +++ /dev/null @@ -1,22 +0,0 @@ -using DiscountVariants = Orb.Models.DiscountVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Discount -{ - internal Discount() { } - - public static DiscountVariants::PercentageDiscount Create(PercentageDiscount value) => - new(value); - - public static DiscountVariants::TrialDiscount Create(TrialDiscount value) => new(value); - - public static DiscountVariants::UsageDiscount Create(UsageDiscount value) => new(value); - - public static DiscountVariants::AmountDiscount Create(AmountDiscount value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/DiscountVariants/All.cs b/src/Orb/Models/DiscountVariants/All.cs deleted file mode 100644 index e1f866a6..00000000 --- a/src/Orb/Models/DiscountVariants/All.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.DiscountVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PercentageDiscount(Models::PercentageDiscount Value) - : Models::Discount, - Orb::IVariant -{ - public static PercentageDiscount From(Models::PercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class TrialDiscount(Models::TrialDiscount Value) - : Models::Discount, - Orb::IVariant -{ - public static TrialDiscount From(Models::TrialDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class UsageDiscount(Models::UsageDiscount Value) - : Models::Discount, - Orb::IVariant -{ - public static UsageDiscount From(Models::UsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmountDiscount(Models::AmountDiscount Value) - : Models::Discount, - Orb::IVariant -{ - public static AmountDiscount From(Models::AmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Events/Backfills/BackfillCloseParams.cs b/src/Orb/Models/Events/Backfills/BackfillCloseParams.cs index 8f77c0ca..42f38401 100644 --- a/src/Orb/Models/Events/Backfills/BackfillCloseParams.cs +++ b/src/Orb/Models/Events/Backfills/BackfillCloseParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events.Backfills; @@ -10,27 +14,65 @@ namespace Orb.Models.Events.Backfills; /// graphs. Once all of the updates are complete, the backfill's status will transition /// to `reflected`. /// -public sealed record class BackfillCloseParams : Orb::ParamsBase +public sealed record class BackfillCloseParams : ParamsBase { - public required string BackfillID; + public string? BackfillID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public BackfillCloseParams() { } + + public BackfillCloseParams(BackfillCloseParams backfillCloseParams) + : base(backfillCloseParams) { } + + public BackfillCloseParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BackfillCloseParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static BackfillCloseParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/events/backfills/{0}/close", this.BackfillID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/Backfills/BackfillCloseResponse.cs b/src/Orb/Models/Events/Backfills/BackfillCloseResponse.cs index b42f1cdf..78d382a7 100644 --- a/src/Orb/Models/Events/Backfills/BackfillCloseResponse.cs +++ b/src/Orb/Models/Events/Backfills/BackfillCloseResponse.cs @@ -1,9 +1,10 @@ -using BackfillCloseResponseProperties = Orb.Models.Events.Backfills.BackfillCloseResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Events.Backfills; @@ -12,75 +13,45 @@ namespace Orb.Models.Events.Backfills; /// A backfill represents an update to historical usage data, adding or replacing /// events in a timeframe. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BackfillCloseResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BackfillCloseResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// If in the future, the time at which the backfill will automatically close. /// If in the past, the time at which the backfill was closed. /// - public required System::DateTime? CloseTime + public required System::DateTimeOffset? CloseTime { get { - if (!this.Properties.TryGetValue("close_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "close_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "close_time"); } - set { this.Properties["close_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "close_time", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// - /// The Orb-generated ID of the customer to which this backfill is scoped. If `null`, - /// this backfill is scoped to all customers. + /// The Orb-generated ID of the customer to which this backfill is scoped. If + /// `null`, this backfill is scoped to all customers. /// public required string? CustomerID { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } } /// @@ -88,115 +59,70 @@ public required string? CustomerID /// public required long EventsIngested { - get - { - if (!this.Properties.TryGetValue("events_ingested", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "events_ingested", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["events_ingested"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "events_ingested"); } + init { JsonModel.Set(this._rawData, "events_ingested", value); } } /// /// If `true`, existing events in the backfill's timeframe will be replaced with - /// the newly ingested events associated with the backfill. If `false`, newly ingested - /// events will be added to the existing events. + /// the newly ingested events associated with the backfill. If `false`, newly + /// ingested events will be added to the existing events. /// public required bool ReplaceExistingEvents { - get - { - if ( - !this.Properties.TryGetValue( - "replace_existing_events", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replace_existing_events", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replace_existing_events"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "replace_existing_events"); } + init { JsonModel.Set(this._rawData, "replace_existing_events", value); } } /// /// The time at which this backfill was reverted. /// - public required System::DateTime? RevertedAt + public required System::DateTimeOffset? RevertedAt { get { - if (!this.Properties.TryGetValue("reverted_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reverted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "reverted_at"); } - set { this.Properties["reverted_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "reverted_at", value); } } /// /// The status of the backfill. /// - public required BackfillCloseResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required System::DateTime TimeframeEnd + public required System::DateTimeOffset TimeframeEnd { get { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } } - public required System::DateTime TimeframeStart + public required System::DateTimeOffset TimeframeStart { get { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } } /// @@ -205,19 +131,11 @@ public required bool ReplaceExistingEvents /// public string? DeprecationFilter { - get - { - if (!this.Properties.TryGetValue("deprecation_filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["deprecation_filter"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "deprecation_filter"); } + init { JsonModel.Set(this._rawData, "deprecation_filter", value); } } + /// public override void Validate() { _ = this.ID; @@ -235,18 +153,88 @@ public override void Validate() public BackfillCloseResponse() { } + public BackfillCloseResponse(BackfillCloseResponse backfillCloseResponse) + : base(backfillCloseResponse) { } + + public BackfillCloseResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BackfillCloseResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BackfillCloseResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BackfillCloseResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BackfillCloseResponseFromRaw : IFromRawJson +{ + /// + public BackfillCloseResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BackfillCloseResponse.FromRawUnchecked(rawData); +} + +/// +/// The status of the backfill. +/// +[JsonConverter(typeof(BackfillCloseResponseStatusConverter))] +public enum BackfillCloseResponseStatus +{ + Pending, + Reflected, + PendingRevert, + Reverted, +} + +sealed class BackfillCloseResponseStatusConverter : JsonConverter +{ + public override BackfillCloseResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => BackfillCloseResponseStatus.Pending, + "reflected" => BackfillCloseResponseStatus.Reflected, + "pending_revert" => BackfillCloseResponseStatus.PendingRevert, + "reverted" => BackfillCloseResponseStatus.Reverted, + _ => (BackfillCloseResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BackfillCloseResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + BackfillCloseResponseStatus.Pending => "pending", + BackfillCloseResponseStatus.Reflected => "reflected", + BackfillCloseResponseStatus.PendingRevert => "pending_revert", + BackfillCloseResponseStatus.Reverted => "reverted", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Events/Backfills/BackfillCloseResponseProperties/Status.cs b/src/Orb/Models/Events/Backfills/BackfillCloseResponseProperties/Status.cs deleted file mode 100644 index c1e5ff6a..00000000 --- a/src/Orb/Models/Events/Backfills/BackfillCloseResponseProperties/Status.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Backfills.BackfillCloseResponseProperties; - -/// -/// The status of the backfill. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Reflected = new("reflected"); - - public static readonly Status PendingRevert = new("pending_revert"); - - public static readonly Status Reverted = new("reverted"); - - readonly string _value = value; - - public enum Value - { - Pending, - Reflected, - PendingRevert, - Reverted, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "reflected" => Value.Reflected, - "pending_revert" => Value.PendingRevert, - "reverted" => Value.Reverted, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Events/Backfills/BackfillCreateParams.cs b/src/Orb/Models/Events/Backfills/BackfillCreateParams.cs index c4a0b9ef..fe3dd8c0 100644 --- a/src/Orb/Models/Events/Backfills/BackfillCreateParams.cs +++ b/src/Orb/Models/Events/Backfills/BackfillCreateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events.Backfills; @@ -12,100 +14,83 @@ namespace Orb.Models.Events.Backfills; /// are older than the ingestion grace period. Performing a backfill in Orb involves /// 3 steps: /// -/// 1. Create the backfill, specifying its parameters. 2. [Ingest](ingest) usage events, -/// referencing the backfill (query parameter `backfill_id`). 3. [Close](close-backfill) -/// the backfill, propagating the update in past usage throughout Orb. +/// 1. Create the backfill, specifying its parameters. 2. [Ingest](ingest) usage +/// events, referencing the backfill (query parameter `backfill_id`). 3. [Close](close-backfill) +/// the backfill, propagating the update in past usage throughout Orb. /// -/// Changes from a backfill are not reflected until the backfill is closed, so you -/// won’t need to worry about your customers seeing partially updated usage data. -/// Backfills are also reversible, so you’ll be able to revert a backfill if you’ve -/// made a mistake. +/// Changes from a backfill are not reflected until the backfill is closed, +/// so you won’t need to worry about your customers seeing partially updated usage +/// data. Backfills are also reversible, so you’ll be able to revert a backfill if +/// you’ve made a mistake. /// -/// This endpoint will return a backfill object, which contains an `id`. That `id` -/// can then be used as the `backfill_id` query parameter to the event ingestion endpoint -/// to associate ingested events with this backfill. The effects (e.g. updated usage -/// graphs) of this backfill will not take place until the backfill is closed. +/// This endpoint will return a backfill object, which contains an `id`. That +/// `id` can then be used as the `backfill_id` query parameter to the event ingestion +/// endpoint to associate ingested events with this backfill. The effects (e.g. updated +/// usage graphs) of this backfill will not take place until the backfill is closed. /// -/// If the `replace_existing_events` is `true`, existing events in the backfill's +/// If the `replace_existing_events` is `true`, existing events in the backfill's /// timeframe will be replaced with the newly ingested events associated with the -/// backfill. If `false`, newly ingested events will be added to the existing events. +/// backfill. If `false`, newly ingested events will be added to the existing events. /// -/// If a `customer_id` or `external_customer_id` is specified, the backfill will only -/// affect events for that customer. If neither is specified, the backfill will affect -/// all customers. +/// If a `customer_id` or `external_customer_id` is specified, the backfill +/// will only affect events for that customer. If neither is specified, the backfill +/// will affect all customers. /// -/// When `replace_existing_events` is `true`, this indicates that existing events -/// in the timeframe should no longer be counted towards invoiced usage. In this scenario, -/// the parameter `filter` can be optionally added which enables filtering using [computed -/// properties](/extensibility/advanced-metrics#computed-properties). The expressiveness -/// of computed properties allows you to deprecate existing events based on both a -/// period of time and specific property values. +/// When `replace_existing_events` is `true`, this indicates that existing +/// events in the timeframe should no longer be counted towards invoiced usage. In +/// this scenario, the parameter `deprecation_filter` can be optionally added which +/// enables filtering using [computed properties](/extensibility/advanced-metrics#computed-properties). +/// The expressiveness of computed properties allows you to deprecate existing events +/// based on both a period of time and specific property values. +/// +/// You may not have multiple backfills in a pending or pending_revert state +/// with overlapping timeframes. /// -public sealed record class BackfillCreateParams : Orb::ParamsBase +public sealed record class BackfillCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// - /// The (exclusive) end of the usage timeframe affected by this backfill. By default, - /// Orb allows backfills up to 31 days in duration at a time. Reach out to discuss - /// extending this limit and your use case. + /// The (exclusive) end of the usage timeframe affected by this backfill. By + /// default, Orb allows backfills up to 31 days in duration at a time. Reach + /// out to discuss extending this limit and your use case. /// - public required System::DateTime TimeframeEnd + public required DateTimeOffset TimeframeEnd { get { - if (!this.BodyProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct(this.RawBodyData, "timeframe_end"); } + init { JsonModel.Set(this._rawBodyData, "timeframe_end", value); } } /// - /// The (inclusive) start of the usage timeframe affected by this backfill. By default, - /// Orb allows backfills up to 31 days in duration at a time. Reach out to discuss - /// extending this limit and your use case. + /// The (inclusive) start of the usage timeframe affected by this backfill. By + /// default, Orb allows backfills up to 31 days in duration at a time. Reach + /// out to discuss extending this limit and your use case. /// - public required System::DateTime TimeframeStart + public required DateTimeOffset TimeframeStart { get { - if (!this.BodyProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct(this.RawBodyData, "timeframe_start"); } + init { JsonModel.Set(this._rawBodyData, "timeframe_start", value); } } /// - /// The time at which no more events will be accepted for this backfill. The backfill - /// will automatically begin reflecting throughout Orb at the close time. If not - /// specified, it will default to 1 day after the creation of the backfill. + /// The time at which no more events will be accepted for this backfill. The + /// backfill will automatically begin reflecting throughout Orb at the close + /// time. If not specified, it will default to 1 day after the creation of the backfill. /// - public System::DateTime? CloseTime + public DateTimeOffset? CloseTime { - get - { - if (!this.BodyProperties.TryGetValue("close_time", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["close_time"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "close_time"); } + init { JsonModel.Set(this._rawBodyData, "close_time", value); } } /// @@ -114,14 +99,8 @@ public sealed record class BackfillCreateParams : Orb::ParamsBase /// public string? CustomerID { - get - { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } } /// @@ -130,24 +109,8 @@ public string? CustomerID /// public string? DeprecationFilter { - get - { - if ( - !this.BodyProperties.TryGetValue( - "deprecation_filter", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["deprecation_filter"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "deprecation_filter"); } + init { JsonModel.Set(this._rawBodyData, "deprecation_filter", value); } } /// @@ -156,24 +119,8 @@ public string? DeprecationFilter /// public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } /// @@ -184,46 +131,89 @@ public bool? ReplaceExistingEvents { get { - if ( - !this.BodyProperties.TryGetValue( - "replace_existing_events", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawBodyData, "replace_existing_events"); } - set + init { - this.BodyProperties["replace_existing_events"] = - Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "replace_existing_events", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public BackfillCreateParams() { } + + public BackfillCreateParams(BackfillCreateParams backfillCreateParams) + : base(backfillCreateParams) + { + this._rawBodyData = [.. backfillCreateParams._rawBodyData]; + } + + public BackfillCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BackfillCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static BackfillCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/events/backfills") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/events/backfills") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/Backfills/BackfillCreateResponse.cs b/src/Orb/Models/Events/Backfills/BackfillCreateResponse.cs index a3b9b824..9f2d6fb3 100644 --- a/src/Orb/Models/Events/Backfills/BackfillCreateResponse.cs +++ b/src/Orb/Models/Events/Backfills/BackfillCreateResponse.cs @@ -1,9 +1,10 @@ -using BackfillCreateResponseProperties = Orb.Models.Events.Backfills.BackfillCreateResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Events.Backfills; @@ -12,75 +13,45 @@ namespace Orb.Models.Events.Backfills; /// A backfill represents an update to historical usage data, adding or replacing /// events in a timeframe. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BackfillCreateResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BackfillCreateResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// If in the future, the time at which the backfill will automatically close. /// If in the past, the time at which the backfill was closed. /// - public required System::DateTime? CloseTime + public required System::DateTimeOffset? CloseTime { get { - if (!this.Properties.TryGetValue("close_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "close_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "close_time"); } - set { this.Properties["close_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "close_time", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// - /// The Orb-generated ID of the customer to which this backfill is scoped. If `null`, - /// this backfill is scoped to all customers. + /// The Orb-generated ID of the customer to which this backfill is scoped. If + /// `null`, this backfill is scoped to all customers. /// public required string? CustomerID { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } } /// @@ -88,115 +59,69 @@ public required string? CustomerID /// public required long EventsIngested { - get - { - if (!this.Properties.TryGetValue("events_ingested", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "events_ingested", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["events_ingested"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "events_ingested"); } + init { JsonModel.Set(this._rawData, "events_ingested", value); } } /// /// If `true`, existing events in the backfill's timeframe will be replaced with - /// the newly ingested events associated with the backfill. If `false`, newly ingested - /// events will be added to the existing events. + /// the newly ingested events associated with the backfill. If `false`, newly + /// ingested events will be added to the existing events. /// public required bool ReplaceExistingEvents { - get - { - if ( - !this.Properties.TryGetValue( - "replace_existing_events", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replace_existing_events", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replace_existing_events"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "replace_existing_events"); } + init { JsonModel.Set(this._rawData, "replace_existing_events", value); } } /// /// The time at which this backfill was reverted. /// - public required System::DateTime? RevertedAt + public required System::DateTimeOffset? RevertedAt { get { - if (!this.Properties.TryGetValue("reverted_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reverted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "reverted_at"); } - set { this.Properties["reverted_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "reverted_at", value); } } /// /// The status of the backfill. /// - public required BackfillCreateResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "status"); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required System::DateTime TimeframeEnd + public required System::DateTimeOffset TimeframeEnd { get { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } } - public required System::DateTime TimeframeStart + public required System::DateTimeOffset TimeframeStart { get { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } } /// @@ -205,19 +130,11 @@ public required bool ReplaceExistingEvents /// public string? DeprecationFilter { - get - { - if (!this.Properties.TryGetValue("deprecation_filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["deprecation_filter"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "deprecation_filter"); } + init { JsonModel.Set(this._rawData, "deprecation_filter", value); } } + /// public override void Validate() { _ = this.ID; @@ -235,18 +152,88 @@ public override void Validate() public BackfillCreateResponse() { } + public BackfillCreateResponse(BackfillCreateResponse backfillCreateResponse) + : base(backfillCreateResponse) { } + + public BackfillCreateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BackfillCreateResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BackfillCreateResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BackfillCreateResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BackfillCreateResponseFromRaw : IFromRawJson +{ + /// + public BackfillCreateResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BackfillCreateResponse.FromRawUnchecked(rawData); +} + +/// +/// The status of the backfill. +/// +[JsonConverter(typeof(global::Orb.Models.Events.Backfills.StatusConverter))] +public enum Status +{ + Pending, + Reflected, + PendingRevert, + Reverted, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.Events.Backfills.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => global::Orb.Models.Events.Backfills.Status.Pending, + "reflected" => global::Orb.Models.Events.Backfills.Status.Reflected, + "pending_revert" => global::Orb.Models.Events.Backfills.Status.PendingRevert, + "reverted" => global::Orb.Models.Events.Backfills.Status.Reverted, + _ => (global::Orb.Models.Events.Backfills.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Events.Backfills.Status value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Events.Backfills.Status.Pending => "pending", + global::Orb.Models.Events.Backfills.Status.Reflected => "reflected", + global::Orb.Models.Events.Backfills.Status.PendingRevert => "pending_revert", + global::Orb.Models.Events.Backfills.Status.Reverted => "reverted", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Events/Backfills/BackfillCreateResponseProperties/Status.cs b/src/Orb/Models/Events/Backfills/BackfillCreateResponseProperties/Status.cs deleted file mode 100644 index b463f1f1..00000000 --- a/src/Orb/Models/Events/Backfills/BackfillCreateResponseProperties/Status.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Backfills.BackfillCreateResponseProperties; - -/// -/// The status of the backfill. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Reflected = new("reflected"); - - public static readonly Status PendingRevert = new("pending_revert"); - - public static readonly Status Reverted = new("reverted"); - - readonly string _value = value; - - public enum Value - { - Pending, - Reflected, - PendingRevert, - Reverted, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "reflected" => Value.Reflected, - "pending_revert" => Value.PendingRevert, - "reverted" => Value.Reverted, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Events/Backfills/BackfillFetchParams.cs b/src/Orb/Models/Events/Backfills/BackfillFetchParams.cs index 3f7ef357..0fc8a9fa 100644 --- a/src/Orb/Models/Events/Backfills/BackfillFetchParams.cs +++ b/src/Orb/Models/Events/Backfills/BackfillFetchParams.cs @@ -1,33 +1,75 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events.Backfills; /// /// This endpoint is used to fetch a backfill given an identifier. /// -public sealed record class BackfillFetchParams : Orb::ParamsBase +public sealed record class BackfillFetchParams : ParamsBase { - public required string BackfillID; + public string? BackfillID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public BackfillFetchParams() { } + + public BackfillFetchParams(BackfillFetchParams backfillFetchParams) + : base(backfillFetchParams) { } + + public BackfillFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BackfillFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static BackfillFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/events/backfills/{0}", this.BackfillID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/Backfills/BackfillFetchResponse.cs b/src/Orb/Models/Events/Backfills/BackfillFetchResponse.cs index 64251444..6a7ff325 100644 --- a/src/Orb/Models/Events/Backfills/BackfillFetchResponse.cs +++ b/src/Orb/Models/Events/Backfills/BackfillFetchResponse.cs @@ -1,9 +1,10 @@ -using BackfillFetchResponseProperties = Orb.Models.Events.Backfills.BackfillFetchResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Events.Backfills; @@ -12,75 +13,45 @@ namespace Orb.Models.Events.Backfills; /// A backfill represents an update to historical usage data, adding or replacing /// events in a timeframe. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BackfillFetchResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BackfillFetchResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// If in the future, the time at which the backfill will automatically close. /// If in the past, the time at which the backfill was closed. /// - public required System::DateTime? CloseTime + public required System::DateTimeOffset? CloseTime { get { - if (!this.Properties.TryGetValue("close_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "close_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "close_time"); } - set { this.Properties["close_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "close_time", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// - /// The Orb-generated ID of the customer to which this backfill is scoped. If `null`, - /// this backfill is scoped to all customers. + /// The Orb-generated ID of the customer to which this backfill is scoped. If + /// `null`, this backfill is scoped to all customers. /// public required string? CustomerID { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } } /// @@ -88,115 +59,70 @@ public required string? CustomerID /// public required long EventsIngested { - get - { - if (!this.Properties.TryGetValue("events_ingested", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "events_ingested", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["events_ingested"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "events_ingested"); } + init { JsonModel.Set(this._rawData, "events_ingested", value); } } /// /// If `true`, existing events in the backfill's timeframe will be replaced with - /// the newly ingested events associated with the backfill. If `false`, newly ingested - /// events will be added to the existing events. + /// the newly ingested events associated with the backfill. If `false`, newly + /// ingested events will be added to the existing events. /// public required bool ReplaceExistingEvents { - get - { - if ( - !this.Properties.TryGetValue( - "replace_existing_events", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replace_existing_events", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replace_existing_events"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "replace_existing_events"); } + init { JsonModel.Set(this._rawData, "replace_existing_events", value); } } /// /// The time at which this backfill was reverted. /// - public required System::DateTime? RevertedAt + public required System::DateTimeOffset? RevertedAt { get { - if (!this.Properties.TryGetValue("reverted_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reverted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "reverted_at"); } - set { this.Properties["reverted_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "reverted_at", value); } } /// /// The status of the backfill. /// - public required BackfillFetchResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required System::DateTime TimeframeEnd + public required System::DateTimeOffset TimeframeEnd { get { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } } - public required System::DateTime TimeframeStart + public required System::DateTimeOffset TimeframeStart { get { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } } /// @@ -205,19 +131,11 @@ public required bool ReplaceExistingEvents /// public string? DeprecationFilter { - get - { - if (!this.Properties.TryGetValue("deprecation_filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["deprecation_filter"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "deprecation_filter"); } + init { JsonModel.Set(this._rawData, "deprecation_filter", value); } } + /// public override void Validate() { _ = this.ID; @@ -235,18 +153,88 @@ public override void Validate() public BackfillFetchResponse() { } + public BackfillFetchResponse(BackfillFetchResponse backfillFetchResponse) + : base(backfillFetchResponse) { } + + public BackfillFetchResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BackfillFetchResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BackfillFetchResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BackfillFetchResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BackfillFetchResponseFromRaw : IFromRawJson +{ + /// + public BackfillFetchResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BackfillFetchResponse.FromRawUnchecked(rawData); +} + +/// +/// The status of the backfill. +/// +[JsonConverter(typeof(BackfillFetchResponseStatusConverter))] +public enum BackfillFetchResponseStatus +{ + Pending, + Reflected, + PendingRevert, + Reverted, +} + +sealed class BackfillFetchResponseStatusConverter : JsonConverter +{ + public override BackfillFetchResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => BackfillFetchResponseStatus.Pending, + "reflected" => BackfillFetchResponseStatus.Reflected, + "pending_revert" => BackfillFetchResponseStatus.PendingRevert, + "reverted" => BackfillFetchResponseStatus.Reverted, + _ => (BackfillFetchResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BackfillFetchResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + BackfillFetchResponseStatus.Pending => "pending", + BackfillFetchResponseStatus.Reflected => "reflected", + BackfillFetchResponseStatus.PendingRevert => "pending_revert", + BackfillFetchResponseStatus.Reverted => "reverted", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Events/Backfills/BackfillFetchResponseProperties/Status.cs b/src/Orb/Models/Events/Backfills/BackfillFetchResponseProperties/Status.cs deleted file mode 100644 index 539e668a..00000000 --- a/src/Orb/Models/Events/Backfills/BackfillFetchResponseProperties/Status.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Backfills.BackfillFetchResponseProperties; - -/// -/// The status of the backfill. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Reflected = new("reflected"); - - public static readonly Status PendingRevert = new("pending_revert"); - - public static readonly Status Reverted = new("reverted"); - - readonly string _value = value; - - public enum Value - { - Pending, - Reflected, - PendingRevert, - Reverted, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "reflected" => Value.Reflected, - "pending_revert" => Value.PendingRevert, - "reverted" => Value.Reverted, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Events/Backfills/BackfillListPage.cs b/src/Orb/Models/Events/Backfills/BackfillListPage.cs new file mode 100644 index 00000000..6057e514 --- /dev/null +++ b/src/Orb/Models/Events/Backfills/BackfillListPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services.Events; + +namespace Orb.Models.Events.Backfills; + +public sealed class BackfillListPage( + IBackfillService service, + BackfillListParams parameters, + BackfillListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Events/Backfills/BackfillListPageResponse.cs b/src/Orb/Models/Events/Backfills/BackfillListPageResponse.cs index fea123ef..fe0790d9 100644 --- a/src/Orb/Models/Events/Backfills/BackfillListPageResponse.cs +++ b/src/Orb/Models/Events/Backfills/BackfillListPageResponse.cs @@ -1,52 +1,36 @@ -using BackfillListPageResponseProperties = Orb.Models.Events.Backfills.BackfillListPageResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events.Backfills; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BackfillListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class BackfillListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +42,35 @@ public override void Validate() public BackfillListPageResponse() { } + public BackfillListPageResponse(BackfillListPageResponse backfillListPageResponse) + : base(backfillListPageResponse) { } + + public BackfillListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BackfillListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BackfillListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BackfillListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class BackfillListPageResponseFromRaw : IFromRawJson +{ + /// + public BackfillListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BackfillListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Events/Backfills/BackfillListPageResponseProperties/Data.cs b/src/Orb/Models/Events/Backfills/BackfillListPageResponseProperties/Data.cs deleted file mode 100644 index aa8e902c..00000000 --- a/src/Orb/Models/Events/Backfills/BackfillListPageResponseProperties/Data.cs +++ /dev/null @@ -1,247 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Events.Backfills.BackfillListPageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Backfills.BackfillListPageResponseProperties; - -/// -/// A backfill represents an update to historical usage data, adding or replacing -/// events in a timeframe. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If in the future, the time at which the backfill will automatically close. - /// If in the past, the time at which the backfill was closed. - /// - public required System::DateTime? CloseTime - { - get - { - if (!this.Properties.TryGetValue("close_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "close_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["close_time"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The Orb-generated ID of the customer to which this backfill is scoped. If `null`, - /// this backfill is scoped to all customers. - /// - public required string? CustomerID - { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The number of events ingested in this backfill. - /// - public required long EventsIngested - { - get - { - if (!this.Properties.TryGetValue("events_ingested", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "events_ingested", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["events_ingested"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If `true`, existing events in the backfill's timeframe will be replaced with - /// the newly ingested events associated with the backfill. If `false`, newly ingested - /// events will be added to the existing events. - /// - public required bool ReplaceExistingEvents - { - get - { - if ( - !this.Properties.TryGetValue( - "replace_existing_events", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replace_existing_events", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replace_existing_events"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The time at which this backfill was reverted. - /// - public required System::DateTime? RevertedAt - { - get - { - if (!this.Properties.TryGetValue("reverted_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reverted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reverted_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The status of the backfill. - /// - public required DataProperties::Status Status - { - get - { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); - } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeEnd - { - get - { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeStart - { - get - { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A boolean [computed property](/extensibility/advanced-metrics#computed-properties) - /// used to filter the set of events to deprecate - /// - public string? DeprecationFilter - { - get - { - if (!this.Properties.TryGetValue("deprecation_filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["deprecation_filter"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - _ = this.CloseTime; - _ = this.CreatedAt; - _ = this.CustomerID; - _ = this.EventsIngested; - _ = this.ReplaceExistingEvents; - _ = this.RevertedAt; - this.Status.Validate(); - _ = this.TimeframeEnd; - _ = this.TimeframeStart; - _ = this.DeprecationFilter; - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Events/Backfills/BackfillListPageResponseProperties/DataProperties/Status.cs b/src/Orb/Models/Events/Backfills/BackfillListPageResponseProperties/DataProperties/Status.cs deleted file mode 100644 index 9ed52c83..00000000 --- a/src/Orb/Models/Events/Backfills/BackfillListPageResponseProperties/DataProperties/Status.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Backfills.BackfillListPageResponseProperties.DataProperties; - -/// -/// The status of the backfill. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Reflected = new("reflected"); - - public static readonly Status PendingRevert = new("pending_revert"); - - public static readonly Status Reverted = new("reverted"); - - readonly string _value = value; - - public enum Value - { - Pending, - Reflected, - PendingRevert, - Reverted, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "reflected" => Value.Reflected, - "pending_revert" => Value.PendingRevert, - "reverted" => Value.Reverted, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Events/Backfills/BackfillListParams.cs b/src/Orb/Models/Events/Backfills/BackfillListParams.cs index 50a2e6e1..9d97e5a9 100644 --- a/src/Orb/Models/Events/Backfills/BackfillListParams.cs +++ b/src/Orb/Models/Events/Backfills/BackfillListParams.cs @@ -1,19 +1,22 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events.Backfills; /// /// This endpoint returns a list of all backfills in a list format. /// -/// The list of backfills is ordered starting from the most recently created backfill. -/// The response also includes [`pagination_metadata`](/api-reference/pagination), +/// The list of backfills is ordered starting from the most recently created +/// backfill. The response also includes [`pagination_metadata`](/api-reference/pagination), /// which lets the caller retrieve the next page of results if they exist. More information -/// about pagination can be found in the [Pagination-metadata schema](pagination). +/// about pagination can be found in the [Pagination-metadata schema](pagination). /// -public sealed record class BackfillListParams : Orb::ParamsBase +public sealed record class BackfillListParams : ParamsBase { /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -21,14 +24,8 @@ public sealed record class BackfillListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -36,30 +33,70 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public BackfillListParams() { } + + public BackfillListParams(BackfillListParams backfillListParams) + : base(backfillListParams) { } + + public BackfillListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BackfillListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static BackfillListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/events/backfills") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/events/backfills") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/Backfills/BackfillListResponse.cs b/src/Orb/Models/Events/Backfills/BackfillListResponse.cs new file mode 100644 index 00000000..197580c3 --- /dev/null +++ b/src/Orb/Models/Events/Backfills/BackfillListResponse.cs @@ -0,0 +1,240 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Events.Backfills; + +/// +/// A backfill represents an update to historical usage data, adding or replacing +/// events in a timeframe. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BackfillListResponse : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// If in the future, the time at which the backfill will automatically close. + /// If in the past, the time at which the backfill was closed. + /// + public required System::DateTimeOffset? CloseTime + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "close_time"); + } + init { JsonModel.Set(this._rawData, "close_time", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + /// + /// The Orb-generated ID of the customer to which this backfill is scoped. If + /// `null`, this backfill is scoped to all customers. + /// + public required string? CustomerID + { + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } + } + + /// + /// The number of events ingested in this backfill. + /// + public required long EventsIngested + { + get { return JsonModel.GetNotNullStruct(this.RawData, "events_ingested"); } + init { JsonModel.Set(this._rawData, "events_ingested", value); } + } + + /// + /// If `true`, existing events in the backfill's timeframe will be replaced with + /// the newly ingested events associated with the backfill. If `false`, newly + /// ingested events will be added to the existing events. + /// + public required bool ReplaceExistingEvents + { + get { return JsonModel.GetNotNullStruct(this.RawData, "replace_existing_events"); } + init { JsonModel.Set(this._rawData, "replace_existing_events", value); } + } + + /// + /// The time at which this backfill was reverted. + /// + public required System::DateTimeOffset? RevertedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "reverted_at"); + } + init { JsonModel.Set(this._rawData, "reverted_at", value); } + } + + /// + /// The status of the backfill. + /// + public required ApiEnum Status + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); + } + init { JsonModel.Set(this._rawData, "status", value); } + } + + public required System::DateTimeOffset TimeframeEnd + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); + } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } + } + + public required System::DateTimeOffset TimeframeStart + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); + } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } + } + + /// + /// A boolean [computed property](/extensibility/advanced-metrics#computed-properties) + /// used to filter the set of events to deprecate + /// + public string? DeprecationFilter + { + get { return JsonModel.GetNullableClass(this.RawData, "deprecation_filter"); } + init { JsonModel.Set(this._rawData, "deprecation_filter", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CloseTime; + _ = this.CreatedAt; + _ = this.CustomerID; + _ = this.EventsIngested; + _ = this.ReplaceExistingEvents; + _ = this.RevertedAt; + this.Status.Validate(); + _ = this.TimeframeEnd; + _ = this.TimeframeStart; + _ = this.DeprecationFilter; + } + + public BackfillListResponse() { } + + public BackfillListResponse(BackfillListResponse backfillListResponse) + : base(backfillListResponse) { } + + public BackfillListResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BackfillListResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BackfillListResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BackfillListResponseFromRaw : IFromRawJson +{ + /// + public BackfillListResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BackfillListResponse.FromRawUnchecked(rawData); +} + +/// +/// The status of the backfill. +/// +[JsonConverter(typeof(BackfillListResponseStatusConverter))] +public enum BackfillListResponseStatus +{ + Pending, + Reflected, + PendingRevert, + Reverted, +} + +sealed class BackfillListResponseStatusConverter : JsonConverter +{ + public override BackfillListResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => BackfillListResponseStatus.Pending, + "reflected" => BackfillListResponseStatus.Reflected, + "pending_revert" => BackfillListResponseStatus.PendingRevert, + "reverted" => BackfillListResponseStatus.Reverted, + _ => (BackfillListResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BackfillListResponseStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BackfillListResponseStatus.Pending => "pending", + BackfillListResponseStatus.Reflected => "reflected", + BackfillListResponseStatus.PendingRevert => "pending_revert", + BackfillListResponseStatus.Reverted => "reverted", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Events/Backfills/BackfillRevertParams.cs b/src/Orb/Models/Events/Backfills/BackfillRevertParams.cs index 3117b17f..ba76b71a 100644 --- a/src/Orb/Models/Events/Backfills/BackfillRevertParams.cs +++ b/src/Orb/Models/Events/Backfills/BackfillRevertParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events.Backfills; @@ -10,30 +14,68 @@ namespace Orb.Models.Events.Backfills; /// of the backfill are undone. Once all effects are undone, the backfill will transition /// to `reverted`. /// -/// If a backfill is reverted before its closed, no usage will be updated as a result -/// of the backfill and it will immediately transition to `reverted`. +/// If a backfill is reverted before its closed, no usage will be updated as +/// a result of the backfill and it will immediately transition to `reverted`. /// -public sealed record class BackfillRevertParams : Orb::ParamsBase +public sealed record class BackfillRevertParams : ParamsBase { - public required string BackfillID; + public string? BackfillID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public BackfillRevertParams() { } + + public BackfillRevertParams(BackfillRevertParams backfillRevertParams) + : base(backfillRevertParams) { } + + public BackfillRevertParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BackfillRevertParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static BackfillRevertParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/events/backfills/{0}/revert", this.BackfillID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/Backfills/BackfillRevertResponse.cs b/src/Orb/Models/Events/Backfills/BackfillRevertResponse.cs index 051c9547..3cca8df8 100644 --- a/src/Orb/Models/Events/Backfills/BackfillRevertResponse.cs +++ b/src/Orb/Models/Events/Backfills/BackfillRevertResponse.cs @@ -1,9 +1,10 @@ -using BackfillRevertResponseProperties = Orb.Models.Events.Backfills.BackfillRevertResponseProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Events.Backfills; @@ -12,75 +13,45 @@ namespace Orb.Models.Events.Backfills; /// A backfill represents an update to historical usage data, adding or replacing /// events in a timeframe. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BackfillRevertResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BackfillRevertResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// If in the future, the time at which the backfill will automatically close. /// If in the past, the time at which the backfill was closed. /// - public required System::DateTime? CloseTime + public required System::DateTimeOffset? CloseTime { get { - if (!this.Properties.TryGetValue("close_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "close_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "close_time"); } - set { this.Properties["close_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "close_time", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// - /// The Orb-generated ID of the customer to which this backfill is scoped. If `null`, - /// this backfill is scoped to all customers. + /// The Orb-generated ID of the customer to which this backfill is scoped. If + /// `null`, this backfill is scoped to all customers. /// public required string? CustomerID { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } } /// @@ -88,115 +59,70 @@ public required string? CustomerID /// public required long EventsIngested { - get - { - if (!this.Properties.TryGetValue("events_ingested", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "events_ingested", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["events_ingested"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "events_ingested"); } + init { JsonModel.Set(this._rawData, "events_ingested", value); } } /// /// If `true`, existing events in the backfill's timeframe will be replaced with - /// the newly ingested events associated with the backfill. If `false`, newly ingested - /// events will be added to the existing events. + /// the newly ingested events associated with the backfill. If `false`, newly + /// ingested events will be added to the existing events. /// public required bool ReplaceExistingEvents { - get - { - if ( - !this.Properties.TryGetValue( - "replace_existing_events", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replace_existing_events", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replace_existing_events"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "replace_existing_events"); } + init { JsonModel.Set(this._rawData, "replace_existing_events", value); } } /// /// The time at which this backfill was reverted. /// - public required System::DateTime? RevertedAt + public required System::DateTimeOffset? RevertedAt { get { - if (!this.Properties.TryGetValue("reverted_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reverted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "reverted_at"); } - set { this.Properties["reverted_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "reverted_at", value); } } /// /// The status of the backfill. /// - public required BackfillRevertResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required System::DateTime TimeframeEnd + public required System::DateTimeOffset TimeframeEnd { get { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } } - public required System::DateTime TimeframeStart + public required System::DateTimeOffset TimeframeStart { get { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } } /// @@ -205,19 +131,11 @@ public required bool ReplaceExistingEvents /// public string? DeprecationFilter { - get - { - if (!this.Properties.TryGetValue("deprecation_filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["deprecation_filter"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "deprecation_filter"); } + init { JsonModel.Set(this._rawData, "deprecation_filter", value); } } + /// public override void Validate() { _ = this.ID; @@ -235,18 +153,88 @@ public override void Validate() public BackfillRevertResponse() { } + public BackfillRevertResponse(BackfillRevertResponse backfillRevertResponse) + : base(backfillRevertResponse) { } + + public BackfillRevertResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BackfillRevertResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + BackfillRevertResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static BackfillRevertResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BackfillRevertResponseFromRaw : IFromRawJson +{ + /// + public BackfillRevertResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BackfillRevertResponse.FromRawUnchecked(rawData); +} + +/// +/// The status of the backfill. +/// +[JsonConverter(typeof(BackfillRevertResponseStatusConverter))] +public enum BackfillRevertResponseStatus +{ + Pending, + Reflected, + PendingRevert, + Reverted, +} + +sealed class BackfillRevertResponseStatusConverter : JsonConverter +{ + public override BackfillRevertResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => BackfillRevertResponseStatus.Pending, + "reflected" => BackfillRevertResponseStatus.Reflected, + "pending_revert" => BackfillRevertResponseStatus.PendingRevert, + "reverted" => BackfillRevertResponseStatus.Reverted, + _ => (BackfillRevertResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BackfillRevertResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + BackfillRevertResponseStatus.Pending => "pending", + BackfillRevertResponseStatus.Reflected => "reflected", + BackfillRevertResponseStatus.PendingRevert => "pending_revert", + BackfillRevertResponseStatus.Reverted => "reverted", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Events/Backfills/BackfillRevertResponseProperties/Status.cs b/src/Orb/Models/Events/Backfills/BackfillRevertResponseProperties/Status.cs deleted file mode 100644 index d2accf2f..00000000 --- a/src/Orb/Models/Events/Backfills/BackfillRevertResponseProperties/Status.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Backfills.BackfillRevertResponseProperties; - -/// -/// The status of the backfill. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Reflected = new("reflected"); - - public static readonly Status PendingRevert = new("pending_revert"); - - public static readonly Status Reverted = new("reverted"); - - readonly string _value = value; - - public enum Value - { - Pending, - Reflected, - PendingRevert, - Reverted, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "reflected" => Value.Reflected, - "pending_revert" => Value.PendingRevert, - "reverted" => Value.Reverted, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Events/EventDeprecateParams.cs b/src/Orb/Models/Events/EventDeprecateParams.cs index 3036aca7..3829a234 100644 --- a/src/Orb/Models/Events/EventDeprecateParams.cs +++ b/src/Orb/Models/Events/EventDeprecateParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events; @@ -8,24 +12,25 @@ namespace Orb.Models.Events; /// This endpoint is used to deprecate a single usage event with a given `event_id`. /// `event_id` refers to the `idempotency_key` passed in during ingestion. /// -/// This endpoint will mark the existing event as ignored. Note that if you attempt -/// to re-ingest an event with the same `event_id` as a deprecated event, Orb will -/// return an error. +/// This endpoint will mark the existing event as ignored. Note that if you +/// attempt to re-ingest an event with the same `event_id` as a deprecated event, +/// Orb will return an error. /// -/// This is a powerful and audit-safe mechanism to retroactively deprecate a single -/// event in cases where you need to: * no longer bill for an event that was improperly -/// reported * no longer bill for an event based on the result of an external API -/// call (e.g. call to a payment gateway failed and the user should not be billed) +/// This is a powerful and audit-safe mechanism to retroactively deprecate +/// a single event in cases where you need to: * no longer bill for an event that +/// was improperly reported * no longer bill for an event based on the result of +/// an external API call (e.g. call to a payment gateway failed and the user should +/// not be billed) /// -/// If you want to only change specific properties of an event, but keep the event -/// as part of the billing calculation, use the [Amend event](amend-event) endpoint instead. +/// If you want to only change specific properties of an event, but keep the +/// event as part of the billing calculation, use the [Amend event](amend-event) endpoint instead. /// -/// This API is always audit-safe. The process will still retain the deprecated event, -/// though it will be ignored for billing calculations. For auditing and data fidelity -/// purposes, Orb never overwrites or permanently deletes ingested usage data. +/// This API is always audit-safe. The process will still retain the deprecated +/// event, though it will be ignored for billing calculations. For auditing and data +/// fidelity purposes, Orb never overwrites or permanently deletes ingested usage data. /// -/// ## Request validation * Orb does not accept an `idempotency_key` with the event -/// in this endpoint, since this request is by design idempotent. On retryable +/// ## Request validation * Orb does not accept an `idempotency_key` with the +/// event in this endpoint, since this request is by design idempotent. On retryable /// errors, you should retry the request and assume the deprecation operation has /// not succeeded until receipt of a 2xx. * The event's `timestamp` must fall within /// the customer's current subscription's billing period, or within the grace period @@ -36,29 +41,67 @@ namespace Orb.Models.Events; /// ingested during the initial integration period. We do not allow deprecating /// events for customers not in the Orb system. * By default, no more than 100 events /// can be deprecated for a single customer in a 100 day period. For higher volume -/// updates, consider using the [event backfill](create-backfill) endpoint. +/// updates, consider using the [event backfill](create-backfill) endpoint. /// -public sealed record class EventDeprecateParams : Orb::ParamsBase +public sealed record class EventDeprecateParams : ParamsBase { - public required string EventID; + public string? EventID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public EventDeprecateParams() { } + + public EventDeprecateParams(EventDeprecateParams eventDeprecateParams) + : base(eventDeprecateParams) { } + + public EventDeprecateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventDeprecateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static EventDeprecateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/events/{0}/deprecate", this.EventID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/EventDeprecateResponse.cs b/src/Orb/Models/Events/EventDeprecateResponse.cs index 9341cdbe..775d3711 100644 --- a/src/Orb/Models/Events/EventDeprecateResponse.cs +++ b/src/Orb/Models/Events/EventDeprecateResponse.cs @@ -1,36 +1,25 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EventDeprecateResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventDeprecateResponse : JsonModel { /// /// event_id of the deprecated event, if successfully updated /// public required string Deprecated { - get - { - if (!this.Properties.TryGetValue("deprecated", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "deprecated", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("deprecated"); - } - set { this.Properties["deprecated"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "deprecated"); } + init { JsonModel.Set(this._rawData, "deprecated", value); } } + /// public override void Validate() { _ = this.Deprecated; @@ -38,18 +27,42 @@ public override void Validate() public EventDeprecateResponse() { } + public EventDeprecateResponse(EventDeprecateResponse eventDeprecateResponse) + : base(eventDeprecateResponse) { } + + public EventDeprecateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EventDeprecateResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + EventDeprecateResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static EventDeprecateResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventDeprecateResponse(string deprecated) + : this() + { + this.Deprecated = deprecated; } } + +class EventDeprecateResponseFromRaw : IFromRawJson +{ + /// + public EventDeprecateResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => EventDeprecateResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Events/EventIngestParams.cs b/src/Orb/Models/Events/EventIngestParams.cs index ee596621..01ded658 100644 --- a/src/Orb/Models/Events/EventIngestParams.cs +++ b/src/Orb/Models/Events/EventIngestParams.cs @@ -1,196 +1,192 @@ -using EventIngestParamsProperties = Orb.Models.Events.EventIngestParamsProperties; -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events; /// /// Orb's event ingestion model and API is designed around two core principles: /// -/// 1. **Data fidelity**: The accuracy of your billing model depends on a robust +/// 1. **Data fidelity**: The accuracy of your billing model depends on a robust /// foundation of events. Orb's API protocol encourages usage patterns that ensure /// that your data is consistently complete and correct. 2. **Fast integration**: /// Sending events into Orb requires no tedious setup steps or explicit field schema -/// for your event shape, making it instant to start streaming in usage in real-time. +/// for your event shape, making it instant to start streaming in usage in real-time. /// -/// ## Event shape +/// ## Event shape /// -/// Events are the starting point for all usage calculations in the system, and are -/// simple at their core: +/// Events are the starting point for all usage calculations in the system, +/// and are simple at their core: /// -/// ```ts { // customer_id and external_customer_id are used to // attribute +/// ```ts { // customer_id and external_customer_id are used to // attribute /// usage to a given Customer. Exactly one of these // should be specified in a -/// given ingestion event. +/// given ingestion event. /// -/// // `customer_id` is the Orb generated identifier for the Customer, // which -/// is returned from the Create customer API call. customer_id: string, +/// // `customer_id` is the Orb generated identifier for the Customer, +/// // which is returned from the Create customer API call. customer_id: string, /// -/// // external_customer_id is an alternate identifier which is associated // -/// with a Customer at creation time. This is treated as an alias for // customer_id, -/// and is usually set to an identifier native to your system. external_customer_id: string, +/// // external_customer_id is an alternate identifier which is associated +/// // with a Customer at creation time. This is treated as an alias for // customer_id, +/// and is usually set to an identifier native to your system. external_customer_id: string, /// -/// // A string name identifying the event, usually a usage // action. By convention, -/// this should not contain any whitespace. event_name: string, +/// // A string name identifying the event, usually a usage // action. +/// By convention, this should not contain any whitespace. event_name: string, /// -/// // An ISO 8601 format date with no timezone offset. // This should represent +/// // An ISO 8601 format date with no timezone offset. // This should represent /// the time that usage occurred // and is important to attribute usage to a given /// // billing period. See the notes below on determining the timestamp. // e.g. -/// 2020-12-09T16:09:53Z timestamp: string, +/// 2020-12-09T16:09:53Z timestamp: string, /// -/// // A unique value, generated by the client, that is // used to de-duplicate +/// // A unique value, generated by the client, that is // used to de-duplicate /// events. // Exactly one event with a given // idempotency key will be ingested, -/// which allows for // safe request retries. idempotency_key: string +/// which allows for // safe request retries. idempotency_key: string /// -/// // Optional custom metadata to attach to the event. // This might include +/// // Optional custom metadata to attach to the event. // This might include /// a numeric value used for aggregation, // or a string/boolean value used for /// filtering. // The schema of this dictionary need not be pre-declared, and -/// // properties can be added at any time. properties: { [key: string]?: string -/// | number | boolean, }, } ``` +/// // properties can be added at any time. properties: { [key: string]?: +/// string | number | boolean, }, } ``` /// -/// ## Required fields Because events streamed to Orb are meant to be as flexible -/// as possible, there are only a few required fields in every event. +/// ## Required fields Because events streamed to Orb are meant to be as flexible +/// as possible, there are only a few required fields in every event. /// -/// - We recommend that `idempotency_key` are unique strings that you generated with -/// V4 UUIDs, but only require that they uniquely identify an event (i.e. don’t collide). -/// - The `timestamp` field in the event body will be used to determine which billable -/// period a given event falls into. For example, with a monthly billing cycle starting -/// from the first of December, Orb will calculate metrics based on events that fall -/// into the range `12-01 00:00:00 <= timestamp < 01-01 00:00:00`. +/// - We recommend that `idempotency_key` are unique strings that you generated +/// with V4 UUIDs, but only require that they uniquely identify an event (i.e. don’t +/// collide). - The `timestamp` field in the event body will be used to determine +/// which billable period a given event falls into. For example, with a monthly billing +/// cycle starting from the first of December, Orb will calculate metrics based on +/// events that fall into the range `12-01 00:00:00 <= timestamp < 01-01 00:00:00`. /// -/// ## Logging metadata +/// ## Logging metadata /// -/// Orb allows tagging events with metadata using a flexible properties dictionary. +/// Orb allows tagging events with metadata using a flexible properties dictionary. /// Since Orb does not enforce a rigid schema for this field-set, key-value pairs -/// can be added dynamically as your events evolve. +/// can be added dynamically as your events evolve. /// -/// This dictionary can be helpful for a wide variety of use cases: +/// This dictionary can be helpful for a wide variety of use cases: /// -/// - Numeric properties on events like `compute_time_ms` can later be inputs to our -/// flexible query engine to determine usage. - Logging a region or cluster with each -/// event can help you provide customers more granular visibility into their usage. -/// - If you are using matrix pricing and matching a matrix price key with a property, -/// you should ensure the value for that property is sent as a string. +/// - Numeric properties on events like `compute_time_ms` can later be inputs +/// to our flexible query engine to determine usage. - Logging a region or cluster +/// with each event can help you provide customers more granular visibility into their +/// usage. - If you are using matrix pricing and matching a matrix price key with +/// a property, you should ensure the value for that property is sent as a string. /// -/// We encourage logging this metadata with an eye towards future use cases to ensure -/// full coverage for historical data. The datatype of the value in the properties -/// dictionary is important for metric creation from an event source. Values that -/// you wish to numerically aggregate should be of numeric type in the event. +/// We encourage logging this metadata with an eye towards future use cases +/// to ensure full coverage for historical data. The datatype of the value in the +/// properties dictionary is important for metric creation from an event source. Values +/// that you wish to numerically aggregate should be of numeric type in the event. /// -/// ## Determining event timestamp For cases where usage is being reported in real -/// time as it is occurring, timestamp should correspond to the time that usage occurred. +/// ## Determining event timestamp For cases where usage is being reported in +/// real time as it is occurring, timestamp should correspond to the time that usage occurred. /// -/// In cases where usage is reported in aggregate for a historical timeframe at a -/// regular interval, we recommend setting the event `timestamp` to the midpoint +/// In cases where usage is reported in aggregate for a historical timeframe +/// at a regular interval, we recommend setting the event `timestamp` to the midpoint /// of the interval. As an example, if you have an hourly reporter that sends data /// once an hour for the previous hour of usage, setting the `timestamp` to the half-hour -/// mark will ensure that the usage is counted within the correct period. +/// mark will ensure that the usage is counted within the correct period. /// -/// Note that other time-related fields (e.g. time elapsed) can be added to the properties -/// dictionary as necessary. +/// Note that other time-related fields (e.g. time elapsed) can be added to +/// the properties dictionary as necessary. /// -/// In cases where usage is reported in aggregate for a historical timeframe, the -/// timestamp must be within the grace period set for your account. Events with `timestamp -/// < current_time - grace_period` will not be accepted as a valid event, and will -/// throw validation errors. Enforcing the grace period enables Orb to accurately +/// In cases where usage is reported in aggregate for a historical timeframe, +/// the timestamp must be within the grace period set for your account. Events with +/// `timestamp < current_time - grace_period` will not be accepted as a valid event, +/// and will throw validation errors. Enforcing the grace period enables Orb to accurately /// map usage to the correct billing cycle and ensure that all usage is billed for -/// in the corresponding billing period. +/// in the corresponding billing period. /// -/// In general, Orb does not expect events with future dated timestamps. In cases -/// where the timestamp is at least 24 hours ahead of the current time, the event -/// will not be accepted as a valid event, and will throw validation errors. +/// In general, Orb does not expect events with future dated timestamps. In +/// cases where the timestamp is at least 24 hours ahead of the current time, the +/// event will not be accepted as a valid event, and will throw validation errors. /// -/// ## Event validation +/// ## Event validation /// -/// Orb’s validation ensures that you recognize errors in your events as quickly as -/// possible, and the API provides informative error messages to help you fix problems quickly. +/// Orb’s validation ensures that you recognize errors in your events as quickly +/// as possible, and the API provides informative error messages to help you fix problems quickly. /// -/// We validate the following: +/// We validate the following: /// -/// - Exactly one of `customer_id` and `external_customer_id` should be specified. +/// - Exactly one of `customer_id` and `external_customer_id` should be specified. /// - If the `customer_id` is specified, the customer in Orb must exist. - If the /// `external_customer_id` is specified, the customer in Orb does not need to exist. /// Events will be attributed to any future customers with the `external_customer_id` /// on subscription creation. - `timestamp` must conform to ISO 8601 and represent /// a timestamp at most 1 hour in the future. This timestamp should be sent in UTC -/// timezone (no timezone offset). -/// -/// ## Idempotency and retry semantics -/// -/// Orb's idempotency guarantees allow you to implement safe retry logic in the event -/// of network or machine failures, ensuring data fidelity. Each event in the request -/// payload is associated with an idempotency key, and Orb guarantees that a single -/// idempotency key will be successfully ingested at most once. Note that when Orb -/// encounters events with duplicate idempotency keys and differing event bodies in -/// a batch of events, the entire batch will be rejected. -/// -/// - Successful responses return a 200 HTTP status code. The response contains information -/// about previously processed events. - Requests that return a `4xx` HTTP status -/// code indicate a payload error and contain at least one event with a validation -/// failure. An event with a validation failure can be re-sent to the ingestion endpoint -/// (after the payload is fixed) with the original idempotency key since that key -/// is not marked as processed. - Requests that return a `5xx` HTTP status code indicate -/// a server-side failure. These requests should be retried in their entirety. -/// -/// ## API usage and limits The ingestion API is designed made for real-time streaming -/// ingestion and architected for high throughput. Even if events are later deemed -/// unnecessary or filtered out, we encourage you to log them to Orb if they may -/// be relevant to billing calculations in the future. -/// -/// To take advantage of the real-time features of the Orb platform and avoid any -/// chance of dropped events by producers, we recommend reporting events to Orb frequently. -/// Optionally, events can also be briefly aggregated at the source, as this API accepts -/// an array of event bodies. -/// -/// Orb does not currently enforce a hard rate-limit for API usage or a maximum request -/// payload size, but please give us a heads up if you’re changing either of these -/// factors by an order of magnitude from initial setup. -/// -/// ## Testing in debug mode The ingestion API supports a debug mode, which returns -/// additional verbose output to indicate which event idempotency keys were newly -/// ingested or duplicates from previous requests. To enable this mode, mark `debug=true` -/// as a query parameter. -/// -/// If `debug=true` is not specified, the response will only contain `validation_failed`. +/// timezone (no timezone offset). +/// +/// ## Idempotency and retry semantics +/// +/// Orb's idempotency guarantees allow you to implement safe retry logic in +/// the event of network or machine failures, ensuring data fidelity. Each event in +/// the request payload is associated with an idempotency key, and Orb guarantees +/// that a single idempotency key will be successfully ingested at most once. Note +/// that when Orb encounters events with duplicate idempotency keys and differing +/// event bodies in a batch of events, the entire batch will be rejected. +/// +/// - Successful responses return a 200 HTTP status code. The response contains +/// information about previously processed events. - Requests that return a `4xx` +/// HTTP status code indicate a payload error and contain at least one event with +/// a validation failure. An event with a validation failure can be re-sent to the +/// ingestion endpoint (after the payload is fixed) with the original idempotency +/// key since that key is not marked as processed. - Requests that return a `5xx` +/// HTTP status code indicate a server-side failure. These requests should be retried +/// in their entirety. +/// +/// ## API usage and limits The ingestion API is designed made for real-time +/// streaming ingestion and architected for high throughput. Even if events are later +/// deemed unnecessary or filtered out, we encourage you to log them to Orb if they +/// may be relevant to billing calculations in the future. +/// +/// To take advantage of the real-time features of the Orb platform and avoid +/// any chance of dropped events by producers, we recommend reporting events to Orb +/// frequently. Optionally, events can also be briefly aggregated at the source, as +/// this API accepts an array of event bodies. +/// +/// Orb does not currently enforce a hard rate-limit for API usage or a maximum +/// request payload size, but please give us a heads up if you’re changing either +/// of these factors by an order of magnitude from initial setup. +/// +/// ## Testing in debug mode The ingestion API supports a debug mode, which +/// returns additional verbose output to indicate which event idempotency keys were +/// newly ingested or duplicates from previous requests. To enable this mode, mark +/// `debug=true` as a query parameter. +/// +/// If `debug=true` is not specified, the response will only contain `validation_failed`. /// Orb will still honor the idempotency guarantees set [here](/events-and-metrics/event-ingestion#event-volume-and-concurrency) -/// in all cases. +/// in all cases. /// -/// We strongly recommend that you only use debug mode as part of testing your initial -/// Orb integration. Once you're ready to switch to production, disable debug mode -/// to take advantage of improved performance and maximal throughput. +/// We strongly recommend that you only use debug mode as part of testing your +/// initial Orb integration. Once you're ready to switch to production, disable debug +/// mode to take advantage of improved performance and maximal throughput. /// -/// #### Example: ingestion response with `debug=true` +/// #### Example: ingestion response with `debug=true` /// -/// ```json { "debug": { "duplicate": [], "ingested": [ "B7E83HDMfJPAunXW", +/// ```json { "debug": { "duplicate": [], "ingested": [ "B7E83HDMfJPAunXW", /// "SJs5DQJ3TnwSqEZE", "8SivfDsNKwCeAXim" ] }, "validation_failed": -/// [] } ``` +/// [] } ``` /// -/// #### Example: ingestion response with `debug=false` +/// #### Example: ingestion response with `debug=false` /// -/// ```json { "validation_failed": [] } ``` +/// ```json { "validation_failed": [] } ``` /// -public sealed record class EventIngestParams : Orb::ParamsBase +public sealed record class EventIngestParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required Generic::List Events + public required IReadOnlyList Events { - get - { - if (!this.BodyProperties.TryGetValue("events", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "events", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("events"); - } - set { this.BodyProperties["events"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawBodyData, "events"); } + init { JsonModel.Set(this._rawBodyData, "events", value); } } /// @@ -199,17 +195,8 @@ public sealed record class EventIngestParams : Orb::ParamsBase /// public string? BackfillID { - get - { - if (!this.QueryProperties.TryGetValue("backfill_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["backfill_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "backfill_id"); } + init { JsonModel.Set(this._rawQueryData, "backfill_id", value); } } /// @@ -217,39 +204,199 @@ public string? BackfillID /// public bool? Debug { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "debug"); } + init { - if (!this.QueryProperties.TryGetValue("debug", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "debug", value); } - set { this.QueryProperties["debug"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public EventIngestParams() { } + + public EventIngestParams(EventIngestParams eventIngestParams) + : base(eventIngestParams) + { + this._rawBodyData = [.. eventIngestParams._rawBodyData]; + } + + public EventIngestParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/ingest") + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventIngestParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static EventIngestParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override Uri Url(ClientOptions options) + { + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/ingest") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Event : JsonModel +{ + /// + /// A name to meaningfully identify the action or event type. + /// + public required string EventName + { + get { return JsonModel.GetNotNullClass(this.RawData, "event_name"); } + init { JsonModel.Set(this._rawData, "event_name", value); } + } + + /// + /// A unique value, generated by the client, that is used to de-duplicate events. + /// Exactly one event with a given idempotency key will be ingested, which allows + /// for safe request retries. + /// + public required string IdempotencyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "idempotency_key"); } + init { JsonModel.Set(this._rawData, "idempotency_key", value); } + } + + /// + /// A dictionary of custom properties. Values in this dictionary must be numeric, + /// boolean, or strings. Nested dictionaries are disallowed. + /// + public required IReadOnlyDictionary Properties { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return JsonModel.GetNotNullClass>( + this.RawData, + "properties" + ); } + init { JsonModel.Set(this._rawData, "properties", value); } + } + + /// + /// An ISO 8601 format date with no timezone offset (i.e. UTC). This should represent + /// the time that usage was recorded, and is particularly important to attribute + /// usage to a given billing period. + /// + public required DateTimeOffset Timestamp + { + get { return JsonModel.GetNotNullStruct(this.RawData, "timestamp"); } + init { JsonModel.Set(this._rawData, "timestamp", value); } + } + + /// + /// The Orb Customer identifier + /// + public string? CustomerID + { + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } } + + /// + /// An alias for the Orb customer, whose mapping is specified when creating the customer + /// + public string? ExternalCustomerID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_customer_id"); } + init { JsonModel.Set(this._rawData, "external_customer_id", value); } + } + + /// + public override void Validate() + { + _ = this.EventName; + _ = this.IdempotencyKey; + _ = this.Properties; + _ = this.Timestamp; + _ = this.CustomerID; + _ = this.ExternalCustomerID; + } + + public Event() { } + + public Event(Event event1) + : base(event1) { } + + public Event(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Event(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Event FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventFromRaw : IFromRawJson +{ + /// + public Event FromRawUnchecked(IReadOnlyDictionary rawData) => + Event.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Events/EventIngestParamsProperties/Event.cs b/src/Orb/Models/Events/EventIngestParamsProperties/Event.cs deleted file mode 100644 index 19a7181f..00000000 --- a/src/Orb/Models/Events/EventIngestParamsProperties/Event.cs +++ /dev/null @@ -1,156 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.EventIngestParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Event : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A name to meaningfully identify the action or event type. - /// - public required string EventName - { - get - { - if (!this.Properties.TryGetValue("event_name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "event_name", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("event_name"); - } - set { this.Properties["event_name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A unique value, generated by the client, that is used to de-duplicate events. - /// Exactly one event with a given idempotency key will be ingested, which allows - /// for safe request retries. - /// - public required string IdempotencyKey - { - get - { - if (!this.Properties.TryGetValue("idempotency_key", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "idempotency_key", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("idempotency_key"); - } - set { this.Properties["idempotency_key"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A dictionary of custom properties. Values in this dictionary must be numeric, - /// boolean, or strings. Nested dictionaries are disallowed. - /// - public required Generic::Dictionary Properties1 - { - get - { - if (!this.Properties.TryGetValue("properties", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "properties", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("properties"); - } - set { this.Properties["properties"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date with no timezone offset (i.e. UTC). This should represent - /// the time that usage was recorded, and is particularly important to attribute - /// usage to a given billing period. - /// - public required System::DateTime Timestamp - { - get - { - if (!this.Properties.TryGetValue("timestamp", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timestamp", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timestamp"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The Orb Customer identifier - /// - public string? CustomerID - { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An alias for the Orb customer, whose mapping is specified when creating the customer - /// - public string? ExternalCustomerID - { - get - { - if (!this.Properties.TryGetValue("external_customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.EventName; - _ = this.IdempotencyKey; - foreach (var item in this.Properties1.Values) - { - _ = item; - } - _ = this.Timestamp; - _ = this.CustomerID; - _ = this.ExternalCustomerID; - } - - public Event() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Event(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Event FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Events/EventIngestResponse.cs b/src/Orb/Models/Events/EventIngestResponse.cs index ebfd9bd4..e5c17635 100644 --- a/src/Orb/Models/Events/EventIngestResponse.cs +++ b/src/Orb/Models/Events/EventIngestResponse.cs @@ -1,56 +1,42 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using EventIngestResponseProperties = Orb.Models.Events.EventIngestResponseProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EventIngestResponse : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventIngestResponse : JsonModel { /// /// Contains all failing validation events. In the case of a 200, this array will /// always be empty. This field will always be present. /// - public required Generic::List ValidationFailed + public required IReadOnlyList ValidationFailed { get { - if (!this.Properties.TryGetValue("validation_failed", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "validation_failed", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("validation_failed"); - } - set - { - this.Properties["validation_failed"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "validation_failed" + ); } + init { JsonModel.Set(this._rawData, "validation_failed", value); } } /// - /// Optional debug information (only present when debug=true is passed to the endpoint). - /// Contains ingested and duplicate event idempotency keys. + /// Optional debug information (only present when debug=true is passed to the + /// endpoint). Contains ingested and duplicate event idempotency keys. /// - public EventIngestResponseProperties::Debug? Debug + public Debug? Debug { - get - { - if (!this.Properties.TryGetValue("debug", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["debug"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "debug"); } + init { JsonModel.Set(this._rawData, "debug", value); } } + /// public override void Validate() { foreach (var item in this.ValidationFailed) @@ -62,18 +48,161 @@ public override void Validate() public EventIngestResponse() { } + public EventIngestResponse(EventIngestResponse eventIngestResponse) + : base(eventIngestResponse) { } + + public EventIngestResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EventIngestResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + EventIngestResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static EventIngestResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public EventIngestResponse(List validationFailed) + : this() + { + this.ValidationFailed = validationFailed; + } +} + +class EventIngestResponseFromRaw : IFromRawJson +{ + /// + public EventIngestResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + EventIngestResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ValidationFailed : JsonModel +{ + /// + /// The passed idempotency_key corresponding to the validation_errors + /// + public required string IdempotencyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "idempotency_key"); } + init { JsonModel.Set(this._rawData, "idempotency_key", value); } + } + + /// + /// An array of strings corresponding to validation failures for this idempotency_key. + /// + public required IReadOnlyList ValidationErrors + { + get { return JsonModel.GetNotNullClass>(this.RawData, "validation_errors"); } + init { JsonModel.Set(this._rawData, "validation_errors", value); } + } + + /// + public override void Validate() + { + _ = this.IdempotencyKey; + _ = this.ValidationErrors; + } + + public ValidationFailed() { } + + public ValidationFailed(ValidationFailed validationFailed) + : base(validationFailed) { } + + public ValidationFailed(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ValidationFailed(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ValidationFailed FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ValidationFailedFromRaw : IFromRawJson +{ + /// + public ValidationFailed FromRawUnchecked(IReadOnlyDictionary rawData) => + ValidationFailed.FromRawUnchecked(rawData); +} + +/// +/// Optional debug information (only present when debug=true is passed to the endpoint). +/// Contains ingested and duplicate event idempotency keys. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Debug : JsonModel +{ + public required IReadOnlyList Duplicate + { + get { return JsonModel.GetNotNullClass>(this.RawData, "duplicate"); } + init { JsonModel.Set(this._rawData, "duplicate", value); } + } + + public required IReadOnlyList Ingested + { + get { return JsonModel.GetNotNullClass>(this.RawData, "ingested"); } + init { JsonModel.Set(this._rawData, "ingested", value); } + } + + /// + public override void Validate() + { + _ = this.Duplicate; + _ = this.Ingested; + } + + public Debug() { } + + public Debug(Debug debug) + : base(debug) { } + + public Debug(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Debug(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Debug FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DebugFromRaw : IFromRawJson +{ + /// + public Debug FromRawUnchecked(IReadOnlyDictionary rawData) => + Debug.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Events/EventIngestResponseProperties/Debug.cs b/src/Orb/Models/Events/EventIngestResponseProperties/Debug.cs deleted file mode 100644 index 318a5526..00000000 --- a/src/Orb/Models/Events/EventIngestResponseProperties/Debug.cs +++ /dev/null @@ -1,75 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.EventIngestResponseProperties; - -/// -/// Optional debug information (only present when debug=true is passed to the endpoint). -/// Contains ingested and duplicate event idempotency keys. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Debug : Orb::ModelBase, Orb::IFromRaw -{ - public required Generic::List Duplicate - { - get - { - if (!this.Properties.TryGetValue("duplicate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duplicate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("duplicate"); - } - set { this.Properties["duplicate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::List Ingested - { - get - { - if (!this.Properties.TryGetValue("ingested", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ingested", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("ingested"); - } - set { this.Properties["ingested"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - foreach (var item in this.Duplicate) - { - _ = item; - } - foreach (var item in this.Ingested) - { - _ = item; - } - } - - public Debug() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Debug(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Debug FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Events/EventIngestResponseProperties/ValidationFailed.cs b/src/Orb/Models/Events/EventIngestResponseProperties/ValidationFailed.cs deleted file mode 100644 index e7ce476c..00000000 --- a/src/Orb/Models/Events/EventIngestResponseProperties/ValidationFailed.cs +++ /dev/null @@ -1,79 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.EventIngestResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ValidationFailed : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The passed idempotency_key corresponding to the validation_errors - /// - public required string IdempotencyKey - { - get - { - if (!this.Properties.TryGetValue("idempotency_key", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "idempotency_key", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("idempotency_key"); - } - set { this.Properties["idempotency_key"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An array of strings corresponding to validation failures for this idempotency_key. - /// - public required Generic::List ValidationErrors - { - get - { - if (!this.Properties.TryGetValue("validation_errors", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "validation_errors", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("validation_errors"); - } - set - { - this.Properties["validation_errors"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.IdempotencyKey; - foreach (var item in this.ValidationErrors) - { - _ = item; - } - } - - public ValidationFailed() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ValidationFailed(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ValidationFailed FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Events/EventSearchParams.cs b/src/Orb/Models/Events/EventSearchParams.cs index 88c0d0f1..c8751e28 100644 --- a/src/Orb/Models/Events/EventSearchParams.cs +++ b/src/Orb/Models/Events/EventSearchParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events; @@ -11,103 +13,134 @@ namespace Orb.Models.Events; /// This endpoint returns a filtered set of events for an account in a [paginated /// list format](/api-reference/pagination). /// -/// Note that this is a `POST` endpoint rather than a `GET` endpoint because it employs -/// a JSON body for search criteria rather than query parameters, allowing for a more -/// flexible search syntax. +/// Note that this is a `POST` endpoint rather than a `GET` endpoint because +/// it employs a JSON body for search criteria rather than query parameters, allowing +/// for a more flexible search syntax. /// -/// Note that a search criteria _must_ be specified. Currently, Orb supports the following -/// criteria: - `event_ids`: This is an explicit array of IDs to filter by. Note -/// that an event's ID is the `idempotency_key` that was originally used for ingestion. +/// Note that a search criteria _must_ be specified. Currently, Orb supports +/// the following criteria: - `event_ids`: This is an explicit array of IDs to filter +/// by. Note that an event's ID is the `idempotency_key` that was originally used +/// for ingestion. /// -/// By default, Orb will not throw a `404` if no events matched, Orb will return -/// an empty array for `data` instead. +/// By default, Orb will not throw a `404` if no events matched, Orb will return +/// an empty array for `data` instead. /// -public sealed record class EventSearchParams : Orb::ParamsBase +public sealed record class EventSearchParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// - /// This is an explicit array of IDs to filter by. Note that an event's ID is the - /// idempotency_key that was originally used for ingestion, and this only supports - /// events that have not been amended. Values in this array will be treated case sensitively. + /// This is an explicit array of IDs to filter by. Note that an event's ID is + /// the idempotency_key that was originally used for ingestion, and this only + /// supports events that have not been amended. Values in this array will be + /// treated case sensitively. /// - public required Generic::List EventIDs + public required IReadOnlyList EventIDs { - get - { - if (!this.BodyProperties.TryGetValue("event_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "event_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("event_ids"); - } - set { this.BodyProperties["event_ids"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawBodyData, "event_ids"); } + init { JsonModel.Set(this._rawBodyData, "event_ids", value); } } /// /// The end of the timeframe, exclusive, in which to search events. If not specified, /// the current time is used. /// - public System::DateTime? TimeframeEnd + public DateTimeOffset? TimeframeEnd { get { - if (!this.BodyProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawBodyData, "timeframe_end"); } + init { JsonModel.Set(this._rawBodyData, "timeframe_end", value); } } /// /// The start of the timeframe, inclusive, in which to search events. If not specified, /// the one week ago is used. /// - public System::DateTime? TimeframeStart + public DateTimeOffset? TimeframeStart { get { - if (!this.BodyProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawBodyData, "timeframe_start"); } + init { JsonModel.Set(this._rawBodyData, "timeframe_start", value); } + } + + public EventSearchParams() { } + + public EventSearchParams(EventSearchParams eventSearchParams) + : base(eventSearchParams) + { + this._rawBodyData = [.. eventSearchParams._rawBodyData]; + } + + public EventSearchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventSearchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static EventSearchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/events/search") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/events/search") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/EventSearchResponse.cs b/src/Orb/Models/Events/EventSearchResponse.cs index d3e183f7..0ccaa032 100644 --- a/src/Orb/Models/Events/EventSearchResponse.cs +++ b/src/Orb/Models/Events/EventSearchResponse.cs @@ -1,30 +1,23 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using EventSearchResponseProperties = Orb.Models.Events.EventSearchResponseProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EventSearchResponse : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventSearchResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -35,18 +28,167 @@ public override void Validate() public EventSearchResponse() { } + public EventSearchResponse(EventSearchResponse eventSearchResponse) + : base(eventSearchResponse) { } + + public EventSearchResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EventSearchResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + EventSearchResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static EventSearchResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventSearchResponse(List data) + : this() + { + this.Data = data; + } +} + +class EventSearchResponseFromRaw : IFromRawJson +{ + /// + public EventSearchResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + EventSearchResponse.FromRawUnchecked(rawData); +} + +/// +/// The [Event](/core-concepts#event) resource represents a usage event that has been +/// created for a customer. Events are the core of Orb's usage-based billing model, +/// and are used to calculate the usage charges for a given billing period. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Data : JsonModel +{ + /// + /// A unique value, generated by the client, that is used to de-duplicate events. + /// Exactly one event with a given idempotency key will be ingested, which allows + /// for safe request retries. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The Orb Customer identifier + /// + public required string? CustomerID + { + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } + } + + /// + /// A boolean indicating whether the event is currently deprecated. + /// + public required bool Deprecated + { + get { return JsonModel.GetNotNullStruct(this.RawData, "deprecated"); } + init { JsonModel.Set(this._rawData, "deprecated", value); } + } + + /// + /// A name to meaningfully identify the action or event type. + /// + public required string EventName + { + get { return JsonModel.GetNotNullClass(this.RawData, "event_name"); } + init { JsonModel.Set(this._rawData, "event_name", value); } + } + + /// + /// An alias for the Orb customer, whose mapping is specified when creating the customer + /// + public required string? ExternalCustomerID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_customer_id"); } + init { JsonModel.Set(this._rawData, "external_customer_id", value); } + } + + /// + /// A dictionary of custom properties. Values in this dictionary must be numeric, + /// boolean, or strings. Nested dictionaries are disallowed. + /// + public required IReadOnlyDictionary Properties + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "properties" + ); + } + init { JsonModel.Set(this._rawData, "properties", value); } + } + + /// + /// An ISO 8601 format date with no timezone offset (i.e. UTC). This should represent + /// the time that usage was recorded, and is particularly important to attribute + /// usage to a given billing period. + /// + public required DateTimeOffset Timestamp + { + get { return JsonModel.GetNotNullStruct(this.RawData, "timestamp"); } + init { JsonModel.Set(this._rawData, "timestamp", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CustomerID; + _ = this.Deprecated; + _ = this.EventName; + _ = this.ExternalCustomerID; + _ = this.Properties; + _ = this.Timestamp; + } + + public Data() { } + + public Data(Data data) + : base(data) { } + + public Data(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Data(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } +#pragma warning restore CS8618 + + /// + public static Data FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DataFromRaw : IFromRawJson +{ + /// + public Data FromRawUnchecked(IReadOnlyDictionary rawData) => + Data.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Events/EventSearchResponseProperties/Data.cs b/src/Orb/Models/Events/EventSearchResponseProperties/Data.cs deleted file mode 100644 index 7fc37eb4..00000000 --- a/src/Orb/Models/Events/EventSearchResponseProperties/Data.cs +++ /dev/null @@ -1,183 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.EventSearchResponseProperties; - -/// -/// The [Event](/core-concepts#event) resource represents a usage event that has -/// been created for a customer. Events are the core of Orb's usage-based billing -/// model, and are used to calculate the usage charges for a given billing period. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A unique value, generated by the client, that is used to de-duplicate events. - /// Exactly one event with a given idempotency key will be ingested, which allows - /// for safe request retries. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The Orb Customer identifier - /// - public required string? CustomerID - { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A boolean indicating whether the event is currently deprecated. - /// - public required bool Deprecated - { - get - { - if (!this.Properties.TryGetValue("deprecated", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "deprecated", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["deprecated"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A name to meaningfully identify the action or event type. - /// - public required string EventName - { - get - { - if (!this.Properties.TryGetValue("event_name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "event_name", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("event_name"); - } - set { this.Properties["event_name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An alias for the Orb customer, whose mapping is specified when creating the customer - /// - public required string? ExternalCustomerID - { - get - { - if (!this.Properties.TryGetValue("external_customer_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_customer_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// A dictionary of custom properties. Values in this dictionary must be numeric, - /// boolean, or strings. Nested dictionaries are disallowed. - /// - public required Generic::Dictionary Properties1 - { - get - { - if (!this.Properties.TryGetValue("properties", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "properties", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("properties"); - } - set { this.Properties["properties"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date with no timezone offset (i.e. UTC). This should represent - /// the time that usage was recorded, and is particularly important to attribute - /// usage to a given billing period. - /// - public required System::DateTime Timestamp - { - get - { - if (!this.Properties.TryGetValue("timestamp", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timestamp", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timestamp"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.CustomerID; - _ = this.Deprecated; - _ = this.EventName; - _ = this.ExternalCustomerID; - foreach (var item in this.Properties1.Values) - { - _ = item; - } - _ = this.Timestamp; - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Events/EventUpdateParams.cs b/src/Orb/Models/Events/EventUpdateParams.cs index 3612b8cf..775e31c2 100644 --- a/src/Orb/Models/Events/EventUpdateParams.cs +++ b/src/Orb/Models/Events/EventUpdateParams.cs @@ -1,37 +1,41 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events; /// -/// This endpoint is used to amend a single usage event with a given `event_id`. `event_id` -/// refers to the `idempotency_key` passed in during ingestion. The event will maintain -/// its existing `event_id` after the amendment. +/// This endpoint is used to amend a single usage event with a given `event_id`. +/// `event_id` refers to the `idempotency_key` passed in during ingestion. The event +/// will maintain its existing `event_id` after the amendment. /// -/// This endpoint will mark the existing event as ignored, and Orb will only use the -/// new event passed in the body of this request as the source of truth for that -/// `event_id`. Note that a single event can be amended any number of times, so the -/// same event can be overwritten in subsequent calls to this endpoint. Only a single -/// event with a given `event_id` will be considered the source of truth at any given time. +/// This endpoint will mark the existing event as ignored, and Orb will only +/// use the new event passed in the body of this request as the source of truth for +/// that `event_id`. Note that a single event can be amended any number of times, +/// so the same event can be overwritten in subsequent calls to this endpoint. Only +/// a single event with a given `event_id` will be considered the source of truth +/// at any given time. /// -/// This is a powerful and audit-safe mechanism to retroactively update a single event -/// in cases where you need to: * update an event with new metadata as you iterate -/// on your pricing model * update an event based on the result of an external API -/// call (e.g. call to a payment gateway succeeded or failed) +/// This is a powerful and audit-safe mechanism to retroactively update a single +/// event in cases where you need to: * update an event with new metadata as you +/// iterate on your pricing model * update an event based on the result of an external +/// API call (e.g. call to a payment gateway succeeded or failed) /// -/// This amendment API is always audit-safe. The process will still retain the original -/// event, though it will be ignored for billing calculations. For auditing and data -/// fidelity purposes, Orb never overwrites or permanently deletes ingested usage data. +/// This amendment API is always audit-safe. The process will still retain the +/// original event, though it will be ignored for billing calculations. For auditing +/// and data fidelity purposes, Orb never overwrites or permanently deletes ingested +/// usage data. /// -/// ## Request validation * The `timestamp` of the new event must match the `timestamp` -/// of the existing event already ingested. As with ingestion, all timestamps must -/// be sent in ISO8601 format with UTC timezone offset. * The `customer_id` or `external_customer_id` -/// of the new event must match the `customer_id` or `external_customer_id` of -/// the existing event already ingested. Exactly one of `customer_id` and `external_customer_id` +/// ## Request validation * The `timestamp` of the new event must match the +/// `timestamp` of the existing event already ingested. As with ingestion, all +/// timestamps must be sent in ISO8601 format with UTC timezone offset. * The `customer_id` +/// or `external_customer_id` of the new event must match the `customer_id` or `external_customer_id` +/// of the existing event already ingested. Exactly one of `customer_id` and `external_customer_id` /// should be specified, and similar to ingestion, the ID must identify a Customer /// resource within Orb. Unlike ingestion, for event amendment, we strictly enforce /// that the Customer must be in the Orb system, even during the initial integration @@ -43,52 +47,41 @@ namespace Orb.Models.Events; /// billing period, or within the grace period of the customer's current subscription's /// previous billing period. * By default, no more than 100 events can be amended /// for a single customer in a 100 day period. For higher volume updates, consider -/// using the [event backfill](create-backfill) endpoint. +/// using the [event backfill](create-backfill) endpoint. /// -public sealed record class EventUpdateParams : Orb::ParamsBase +public sealed record class EventUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string EventID; + public string? EventID { get; init; } /// /// A name to meaningfully identify the action or event type. /// public required string EventName { - get - { - if (!this.BodyProperties.TryGetValue("event_name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "event_name", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("event_name"); - } - set { this.BodyProperties["event_name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "event_name"); } + init { JsonModel.Set(this._rawBodyData, "event_name", value); } } /// /// A dictionary of custom properties. Values in this dictionary must be numeric, /// boolean, or strings. Nested dictionaries are disallowed. /// - public required Generic::Dictionary Properties + public required IReadOnlyDictionary Properties { get { - if (!this.BodyProperties.TryGetValue("properties", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "properties", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("properties"); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "properties" + ); } - set { this.BodyProperties["properties"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "properties", value); } } /// @@ -96,19 +89,10 @@ public required string EventName /// the time that usage was recorded, and is particularly important to attribute /// usage to a given billing period. /// - public required System::DateTime Timestamp + public required DateTimeOffset Timestamp { - get - { - if (!this.BodyProperties.TryGetValue("timestamp", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timestamp", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["timestamp"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "timestamp"); } + init { JsonModel.Set(this._rawBodyData, "timestamp", value); } } /// @@ -116,14 +100,8 @@ public required string EventName /// public string? CustomerID { - get - { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } } /// @@ -131,51 +109,82 @@ public string? CustomerID /// public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } + } + + public EventUpdateParams() { } + + public EventUpdateParams(EventUpdateParams eventUpdateParams) + : base(eventUpdateParams) + { + this._rawBodyData = [.. eventUpdateParams._rawBodyData]; + } + + public EventUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static EventUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/events/{0}", this.EventID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/events/{0}", this.EventID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Events/EventUpdateResponse.cs b/src/Orb/Models/Events/EventUpdateResponse.cs index 5c60c79a..5d794c32 100644 --- a/src/Orb/Models/Events/EventUpdateResponse.cs +++ b/src/Orb/Models/Events/EventUpdateResponse.cs @@ -1,34 +1,25 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EventUpdateResponse : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventUpdateResponse : JsonModel { /// /// event_id of the amended event, if successfully ingested /// public required string Amended { - get - { - if (!this.Properties.TryGetValue("amended", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amended", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amended"); - } - set { this.Properties["amended"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amended"); } + init { JsonModel.Set(this._rawData, "amended", value); } } + /// public override void Validate() { _ = this.Amended; @@ -36,18 +27,41 @@ public override void Validate() public EventUpdateResponse() { } + public EventUpdateResponse(EventUpdateResponse eventUpdateResponse) + : base(eventUpdateResponse) { } + + public EventUpdateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EventUpdateResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + EventUpdateResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static EventUpdateResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventUpdateResponse(string amended) + : this() + { + this.Amended = amended; } } + +class EventUpdateResponseFromRaw : IFromRawJson +{ + /// + public EventUpdateResponse FromRawUnchecked(IReadOnlyDictionary rawData) => + EventUpdateResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Events/Volume/EventVolumes.cs b/src/Orb/Models/Events/Volume/EventVolumes.cs index cacea236..29e05faf 100644 --- a/src/Orb/Models/Events/Volume/EventVolumes.cs +++ b/src/Orb/Models/Events/Volume/EventVolumes.cs @@ -1,30 +1,29 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using EventVolumesProperties = Orb.Models.Events.Volume.EventVolumesProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Events.Volume; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EventVolumes : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventVolumes : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -35,18 +34,115 @@ public override void Validate() public EventVolumes() { } + public EventVolumes(EventVolumes eventVolumes) + : base(eventVolumes) { } + + public EventVolumes(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventVolumes(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static EventVolumes FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventVolumes(List data) + : this() + { + this.Data = data; + } +} + +class EventVolumesFromRaw : IFromRawJson +{ + /// + public EventVolumes FromRawUnchecked(IReadOnlyDictionary rawData) => + EventVolumes.FromRawUnchecked(rawData); +} + +/// +/// An EventVolume contains the event volume ingested in an hourly window. The timestamp +/// used for the aggregation is the `timestamp` datetime field on events. +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Events.Volume.Data, + global::Orb.Models.Events.Volume.DataFromRaw + >) +)] +public sealed record class Data : JsonModel +{ + /// + /// The number of events ingested with a timestamp between the timeframe + /// + public required long Count + { + get { return JsonModel.GetNotNullStruct(this.RawData, "count"); } + init { JsonModel.Set(this._rawData, "count", value); } + } + + public required DateTimeOffset TimeframeEnd + { + get { return JsonModel.GetNotNullStruct(this.RawData, "timeframe_end"); } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } + } + + public required DateTimeOffset TimeframeStart + { + get { return JsonModel.GetNotNullStruct(this.RawData, "timeframe_start"); } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } + } + + /// + public override void Validate() + { + _ = this.Count; + _ = this.TimeframeEnd; + _ = this.TimeframeStart; + } + + public Data() { } + + public Data(global::Orb.Models.Events.Volume.Data data) + : base(data) { } + + public Data(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EventVolumes(Generic::Dictionary properties) + [SetsRequiredMembers] + Data(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static EventVolumes FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Events.Volume.Data FromRawUnchecked( + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class DataFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Events.Volume.Data FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Events.Volume.Data.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Events/Volume/EventVolumesProperties/Data.cs b/src/Orb/Models/Events/Volume/EventVolumesProperties/Data.cs deleted file mode 100644 index a0392b4d..00000000 --- a/src/Orb/Models/Events/Volume/EventVolumesProperties/Data.cs +++ /dev/null @@ -1,83 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Events.Volume.EventVolumesProperties; - -/// -/// An EventVolume contains the event volume ingested in an hourly window. The timestamp -/// used for the aggregation is the `timestamp` datetime field on events. -/// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The number of events ingested with a timestamp between the timeframe - /// - public required long Count - { - get - { - if (!this.Properties.TryGetValue("count", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("count", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["count"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeEnd - { - get - { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeStart - { - get - { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Count; - _ = this.TimeframeEnd; - _ = this.TimeframeStart; - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Events/Volume/VolumeListParams.cs b/src/Orb/Models/Events/Volume/VolumeListParams.cs index 192a03ed..3a7f79d8 100644 --- a/src/Orb/Models/Events/Volume/VolumeListParams.cs +++ b/src/Orb/Models/Events/Volume/VolumeListParams.cs @@ -1,48 +1,40 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Events.Volume; /// /// This endpoint returns the event volume for an account in a [paginated list format](/api-reference/pagination). /// -/// The event volume is aggregated by the hour and the [timestamp](/api-reference/event/ingest-events) +/// The event volume is aggregated by the hour and the [timestamp](/api-reference/event/ingest-events) /// field is used to determine which hour an event is associated with. Note, this /// means that late-arriving events increment the volume count for the hour window -/// the timestamp is in, not the latest hour window. +/// the timestamp is in, not the latest hour window. /// -/// Each item in the response contains the count of events aggregated by the hour -/// where the start and end time are hour-aligned and in UTC. When a specific timestamp -/// is passed in for either start or end time, the response includes the hours the -/// timestamp falls in. +/// Each item in the response contains the count of events aggregated by the +/// hour where the start and end time are hour-aligned and in UTC. When a specific +/// timestamp is passed in for either start or end time, the response includes the +/// hours the timestamp falls in. /// -public sealed record class VolumeListParams : Orb::ParamsBase +public sealed record class VolumeListParams : ParamsBase { /// /// The start of the timeframe, inclusive, in which to return event volume. All /// datetime values are converted to UTC time. If the specified time isn't hour-aligned, /// the response includes the event volume count for the hour the time falls in. /// - public required System::DateTime TimeframeStart + public required DateTimeOffset TimeframeStart { get { - if (!this.QueryProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullStruct(this.RawQueryData, "timeframe_start"); } + init { JsonModel.Set(this._rawQueryData, "timeframe_start", value); } } /// @@ -51,14 +43,8 @@ public sealed record class VolumeListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -66,51 +52,93 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } /// /// The end of the timeframe, exclusive, in which to return event volume. If not - /// specified, the current time is used. All datetime values are converted to UTC - /// time.If the specified time isn't hour-aligned, the response includes the event - /// volumecount for the hour the time falls in. + /// specified, the current time is used. All datetime values are converted to + /// UTC time.If the specified time isn't hour-aligned, the response includes + /// the event volumecount for the hour the time falls in. /// - public System::DateTime? TimeframeEnd + public DateTimeOffset? TimeframeEnd { get { - if (!this.QueryProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawQueryData, "timeframe_end"); } - set + init { - this.QueryProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawQueryData, "timeframe_end", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public VolumeListParams() { } + + public VolumeListParams(VolumeListParams volumeListParams) + : base(volumeListParams) { } + + public VolumeListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + VolumeListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static VolumeListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/events/volume") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/events/volume") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/FixedFeeQuantityScheduleEntry.cs b/src/Orb/Models/FixedFeeQuantityScheduleEntry.cs index b69f5b65..71fa0e01 100644 --- a/src/Orb/Models/FixedFeeQuantityScheduleEntry.cs +++ b/src/Orb/Models/FixedFeeQuantityScheduleEntry.cs @@ -1,78 +1,43 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class FixedFeeQuantityScheduleEntry - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class FixedFeeQuantityScheduleEntry : JsonModel { - public required System::DateTime? EndDate + public required DateTimeOffset? EndDate { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } } public required string PriceID { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } } public required double Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } - public required System::DateTime StartDate + public required DateTimeOffset StartDate { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { _ = this.EndDate; @@ -83,18 +48,37 @@ public override void Validate() public FixedFeeQuantityScheduleEntry() { } + public FixedFeeQuantityScheduleEntry( + FixedFeeQuantityScheduleEntry fixedFeeQuantityScheduleEntry + ) + : base(fixedFeeQuantityScheduleEntry) { } + + public FixedFeeQuantityScheduleEntry(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - FixedFeeQuantityScheduleEntry(Generic::Dictionary properties) + [SetsRequiredMembers] + FixedFeeQuantityScheduleEntry(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static FixedFeeQuantityScheduleEntry FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class FixedFeeQuantityScheduleEntryFromRaw : IFromRawJson +{ + /// + public FixedFeeQuantityScheduleEntry FromRawUnchecked( + IReadOnlyDictionary rawData + ) => FixedFeeQuantityScheduleEntry.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/FixedFeeQuantityTransition.cs b/src/Orb/Models/FixedFeeQuantityTransition.cs index f78a2f05..6c5d534c 100644 --- a/src/Orb/Models/FixedFeeQuantityTransition.cs +++ b/src/Orb/Models/FixedFeeQuantityTransition.cs @@ -1,63 +1,37 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class FixedFeeQuantityTransition - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class FixedFeeQuantityTransition : JsonModel { - public required System::DateTime EffectiveDate + public required DateTimeOffset EffectiveDate { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "effective_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "effective_date"); } + init { JsonModel.Set(this._rawData, "effective_date", value); } } public required string PriceID { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } } public required long Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } + /// public override void Validate() { _ = this.EffectiveDate; @@ -67,18 +41,35 @@ public override void Validate() public FixedFeeQuantityTransition() { } + public FixedFeeQuantityTransition(FixedFeeQuantityTransition fixedFeeQuantityTransition) + : base(fixedFeeQuantityTransition) { } + + public FixedFeeQuantityTransition(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - FixedFeeQuantityTransition(Generic::Dictionary properties) + [SetsRequiredMembers] + FixedFeeQuantityTransition(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static FixedFeeQuantityTransition FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class FixedFeeQuantityTransitionFromRaw : IFromRawJson +{ + /// + public FixedFeeQuantityTransition FromRawUnchecked( + IReadOnlyDictionary rawData + ) => FixedFeeQuantityTransition.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Invoice.cs b/src/Orb/Models/Invoice.cs index e0339473..debfe94d 100644 --- a/src/Orb/Models/Invoice.cs +++ b/src/Orb/Models/Invoice.cs @@ -1,9 +1,10 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using InvoiceProperties = Orb.Models.InvoiceProperties; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; @@ -12,23 +13,16 @@ namespace Orb.Models; /// An [`Invoice`](/core-concepts#invoice) is a fundamental billing entity, representing /// the request for payment for a single subscription. This includes a set of line /// items, which correspond to prices in the subscription's plan and can represent -/// fixed recurring fees or usage-based fees. They are generated at the end of a billing -/// period, or as the result of an action, such as a cancellation. +/// fixed recurring fees or usage-based fees. They are generated at the end of a +/// billing period, or as the result of an action, such as a cancellation. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Invoice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Invoice : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -37,87 +31,50 @@ public required string ID /// public required string AmountDue { - get - { - if (!this.Properties.TryGetValue("amount_due", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_due", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_due"); - } - set { this.Properties["amount_due"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_due"); } + init { JsonModel.Set(this._rawData, "amount_due", value); } } - public required InvoiceProperties::AutoCollection AutoCollection + public required InvoiceAutoCollection AutoCollection { get { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("auto_collection"); + return JsonModel.GetNotNullClass( + this.RawData, + "auto_collection" + ); } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } } public required Address? BillingAddress { - get - { - if (!this.Properties.TryGetValue("billing_address", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billing_address", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billing_address"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass
(this.RawData, "billing_address"); } + init { JsonModel.Set(this._rawData, "billing_address", value); } } /// /// The creation time of the resource in Orb. /// - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// /// A list of credit notes associated with the invoice /// - public required Generic::List CreditNotes + public required IReadOnlyList CreditNotes { get { - if (!this.Properties.TryGetValue("credit_notes", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_notes", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("credit_notes"); + return JsonModel.GetNotNullClass>(this.RawData, "credit_notes"); } - set { this.Properties["credit_notes"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "credit_notes", value); } } /// @@ -125,242 +82,171 @@ public required Address? BillingAddress /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } public required CustomerMinified Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } - public required Generic::List CustomerBalanceTransactions + public required IReadOnlyList CustomerBalanceTransactions { get { - if ( - !this.Properties.TryGetValue( - "customer_balance_transactions", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "customer_balance_transactions", - "Missing required argument" - ); + return JsonModel.GetNotNullClass>( + this.RawData, + "customer_balance_transactions" + ); + } + init { JsonModel.Set(this._rawData, "customer_balance_transactions", value); } + } - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("customer_balance_transactions"); - } - set - { - this.Properties["customer_balance_transactions"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// Tax IDs are commonly required to be displayed on customer invoices, which are - /// added to the headers of invoices. - /// - /// ### Supported Tax ID Countries and Types - /// - /// | Country | Type | Description - /// | |----------------|--------------|---------------------------------------------| - /// | Andorra | `ad_nrt` | Andorran NRT Number - /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number - /// | | Australia | `au_abn` | Australian Business Number (AU ABN) - /// | | Australia | `au_arn` | Australian Taxation Office - /// Reference Number | | Austria | `eu_vat` | European VAT Number - /// | | Bahrain | `bh_vat` | Bahraini VAT Number - /// | | Belgium | `eu_vat` | European VAT Number - /// | | Bolivia | `bo_tin` | Bolivian Tax ID - /// | | Brazil | `br_cnpj` | Brazilian CNPJ - /// Number | | Brazil | `br_cpf` | Brazilian CPF - /// Number | | Bulgaria | `bg_uic` | Bulgaria - /// Unified Identification Code | | Bulgaria | `eu_vat` | European - /// VAT Number | | Canada | `ca_bn` | Canadian - /// BN | | Canada | `ca_gst_hst` | Canadian - /// GST/HST Number | | Canada | `ca_pst_bc` | Canadian - /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian - /// PST Number (Manitoba) | | Canada | `ca_pst_sk` | Canadian - /// PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian - /// QST Number (Québec) | | Chile | `cl_tin` | Chilean - /// TIN | | China | `cn_tin` | Chinese - /// Tax ID | | Colombia | `co_nit` | Colombian - /// NIT Number | | Costa Rica | `cr_tin` | Costa - /// Rican Tax ID | | Croatia | `eu_vat` | European - /// VAT Number | | Cyprus | `eu_vat` | European - /// VAT Number | | Czech Republic | `eu_vat` | European - /// VAT Number | | Denmark | `eu_vat` | European - /// VAT Number | | Dominican Republic | `do_rcn` | Dominican - /// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian - /// RUC Number | | Egypt | `eg_tin` | Egyptian - /// Tax Identification Number | | El Salvador | `sv_nit` - /// | El Salvadorian NIT Number | | Estonia | `eu_vat` | - /// European VAT Number | | EU | `eu_oss_vat` | European One Stop Shop - /// VAT Number for non-Union scheme | | Finland | `eu_vat` | European VAT - /// Number | | France | `eu_vat` | European - /// VAT Number | | Georgia | `ge_vat` | - /// Georgian VAT | | Germany | `eu_vat` - /// | European VAT Number | | Greece - /// | `eu_vat` | European VAT Number | | - /// Hong Kong | `hk_br` | Hong Kong BR Number - /// | | Hungary | `eu_vat` | European VAT Number - /// | | Hungary | `hu_tin` | Hungary Tax Number (adószám) - /// | | Iceland | `is_vat` | Icelandic VAT - /// | | India | `in_gst` | Indian GST - /// Number | | Indonesia | `id_npwp` | Indonesian - /// NPWP Number | | Ireland | `eu_vat` | - /// European VAT Number | | Israel | `il_vat` - /// | Israel VAT | | Italy - /// | `eu_vat` | European VAT Number | | - /// Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) - /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' - /// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | - /// Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) - /// | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification - /// Number | | Kenya | `ke_pin` | Kenya Revenue Authority - /// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number - /// | | Liechtenstein | `li_uid` | Liechtensteinian - /// UID Number | | Lithuania | `eu_vat` | European VAT Number - /// | | Luxembourg | `eu_vat` | European VAT Number - /// | | Malaysia | `my_frp` | Malaysian FRP Number - /// | | Malaysia | `my_itn` | Malaysian ITN - /// | | Malaysia | `my_sst` | Malaysian SST Number | - /// | Malta | `eu_vat ` | European VAT Number | | Mexico - /// | `mx_rfc` | Mexican RFC Number | | Netherlands - /// | `eu_vat` | European VAT Number | | New Zealand | - /// `nz_gst` | New Zealand GST Number | | Nigeria | - /// `ng_tin` | Nigerian Tax Identification Number | | Norway | `no_vat` - /// | Norwegian VAT Number | | Norway | `no_voec` | Norwegian - /// VAT on e-commerce Number | | Oman | `om_vat` | Omani VAT Number - /// | | Peru | `pe_ruc` | Peruvian RUC Number - /// | | Philippines | `ph_tin ` | Philippines Tax Identification - /// Number | | Poland | `eu_vat` | European VAT Number - /// | | Portugal | `eu_vat` | European VAT Number | | - /// Romania | `eu_vat` | European VAT Number | | Romania - /// | `ro_tin` | Romanian Tax ID Number | | Russia - /// | `ru_inn` | Russian INN | | Russia | `ru_kpp` - /// | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi - /// Arabia VAT | | Serbia | `rs_pib` | Serbian PIB - /// Number | | Singapore | `sg_gst` | Singaporean GST - /// | | Singapore | `sg_uen` | Singaporean UEN - /// | | Slovakia | `eu_vat` | European VAT Number - /// | | Slovenia | `eu_vat` | European VAT Number - /// | | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) - /// | | South Africa | `za_vat` | South African VAT - /// Number | | South Korea | `kr_brn` | Korean - /// BRN | | Spain | `es_cif` - /// | Spanish NIF Number (previously Spanish CIF Number) | | Spain - /// | `eu_vat` | European VAT Number | | - /// Sweden | `eu_vat` | European VAT Number - /// | | Switzerland | `ch_vat` | Switzerland VAT Number - /// | | Taiwan | `tw_vat` | Taiwanese VAT - /// | | Thailand | `th_vat` | - /// Thai VAT | | Turkey - /// | `tr_tin` | Turkish Tax Identification Number | | Ukraine - /// | `ua_vat` | Ukrainian VAT - /// | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN - /// | | United Kingdom | `eu_vat` | Northern Ireland - /// VAT Number | | United Kingdom | `gb_vat` | United - /// Kingdom VAT Number | | United States | `us_ein` - /// | United States EIN | | Uruguay - /// | `uy_ruc` | Uruguayan RUC Number | | Venezuela - /// | `ve_rif` | Venezuelan RIF Number - /// | | Vietnam | `vn_tin` | Vietnamese Tax ID Number - /// | + /// + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. + /// + /// ### Supported Tax ID Countries and Types + /// + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | /// public required CustomerTaxID? CustomerTaxID { - get - { - if (!this.Properties.TryGetValue("customer_tax_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_tax_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_tax_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "customer_tax_id"); } + init { JsonModel.Set(this._rawData, "customer_tax_id", value); } } /// /// This field is deprecated in favor of `discounts`. If a `discounts` list is - /// provided, the first discount in the list will be returned. If the list is empty, - /// `None` will be returned. + /// provided, the first discount in the list will be returned. If the list is + /// empty, `None` will be returned. /// - public required Json::JsonElement Discount + [System::Obsolete("deprecated")] + public required JsonElement Discount { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } } - public required Generic::List Discounts + public required IReadOnlyList Discounts { get { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discounts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("discounts"); + return JsonModel.GetNotNullClass>(this.RawData, "discounts"); } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discounts", value); } } /// /// When the invoice payment is due. The due date is null if the invoice is not /// yet finalized. /// - public required System::DateTime? DueDate + public required System::DateTimeOffset? DueDate { get { - if (!this.Properties.TryGetValue("due_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "due_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "due_date"); } - set { this.Properties["due_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "due_date", value); } } /// @@ -368,24 +254,16 @@ public required CustomerTaxID? CustomerTaxID /// will be eligible to be issued, otherwise it will be `null`. If `auto-issue` /// is true, the invoice will automatically begin issuing at this time. /// - public required System::DateTime? EligibleToIssueAt + public required System::DateTimeOffset? EligibleToIssueAt { get { - if (!this.Properties.TryGetValue("eligible_to_issue_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "eligible_to_issue_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["eligible_to_issue_at"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawData, + "eligible_to_issue_at" ); } + init { JsonModel.Set(this._rawData, "eligible_to_issue_at", value); } } /// @@ -394,38 +272,20 @@ public required CustomerTaxID? CustomerTaxID /// public required string? HostedInvoiceURL { - get - { - if (!this.Properties.TryGetValue("hosted_invoice_url", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "hosted_invoice_url", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["hosted_invoice_url"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "hosted_invoice_url"); } + init { JsonModel.Set(this._rawData, "hosted_invoice_url", value); } } /// /// The scheduled date of the invoice /// - public required System::DateTime InvoiceDate + public required System::DateTimeOffset InvoiceDate { get { - if (!this.Properties.TryGetValue("invoice_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "invoice_date"); } - set { this.Properties["invoice_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "invoice_date", value); } } /// @@ -435,18 +295,8 @@ public required string? HostedInvoiceURL /// public required string InvoiceNumber { - get - { - if (!this.Properties.TryGetValue("invoice_number", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_number"); - } - set { this.Properties["invoice_number"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "invoice_number"); } + init { JsonModel.Set(this._rawData, "invoice_number", value); } } /// @@ -454,121 +304,70 @@ public required string InvoiceNumber /// public required string? InvoicePdf { - get - { - if (!this.Properties.TryGetValue("invoice_pdf", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_pdf", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice_pdf"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_pdf"); } + init { JsonModel.Set(this._rawData, "invoice_pdf", value); } } - public required InvoiceProperties::InvoiceSource InvoiceSource + public required ApiEnum InvoiceSource { get { - if (!this.Properties.TryGetValue("invoice_source", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_source", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_source"); + return JsonModel.GetNotNullClass>( + this.RawData, + "invoice_source" + ); } - set { this.Properties["invoice_source"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "invoice_source", value); } } /// /// If the invoice failed to issue, this will be the last time it failed to issue /// (even if it is now in a different state.) /// - public required System::DateTime? IssueFailedAt + public required System::DateTimeOffset? IssueFailedAt { get { - if (!this.Properties.TryGetValue("issue_failed_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "issue_failed_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawData, + "issue_failed_at" + ); } - set { this.Properties["issue_failed_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "issue_failed_at", value); } } /// - /// If the invoice has been issued, this will be the time it transitioned to `issued` - /// (even if it is now in a different state.) + /// If the invoice has been issued, this will be the time it transitioned to + /// `issued` (even if it is now in a different state.) /// - public required System::DateTime? IssuedAt + public required System::DateTimeOffset? IssuedAt { get { - if (!this.Properties.TryGetValue("issued_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "issued_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "issued_at"); } - set { this.Properties["issued_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "issued_at", value); } } /// /// The breakdown of prices in this invoice. /// - public required Generic::List LineItems + public required IReadOnlyList LineItems { - get - { - if (!this.Properties.TryGetValue("line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("line_items"); - } - set { this.Properties["line_items"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "line_items"); } + init { JsonModel.Set(this._rawData, "line_items", value); } } public required Maximum? Maximum { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } } public required string? MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// @@ -576,14 +375,8 @@ public required string? MaximumAmount /// public required string? Memo { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("memo", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } } /// @@ -592,208 +385,126 @@ public required string? Memo /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required Minimum? Minimum { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } } public required string? MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } /// /// If the invoice has a status of `paid`, this gives a timestamp when the invoice /// was paid. /// - public required System::DateTime? PaidAt + public required System::DateTimeOffset? PaidAt { - get - { - if (!this.Properties.TryGetValue("paid_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "paid_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["paid_at"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "paid_at"); } + init { JsonModel.Set(this._rawData, "paid_at", value); } } /// /// A list of payment attempts associated with the invoice /// - public required Generic::List PaymentAttempts + public required IReadOnlyList PaymentAttempts { get { - if (!this.Properties.TryGetValue("payment_attempts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_attempts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("payment_attempts"); - } - set - { - this.Properties["payment_attempts"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "payment_attempts" + ); } + init { JsonModel.Set(this._rawData, "payment_attempts", value); } } /// - /// If payment was attempted on this invoice but failed, this will be the time of - /// the most recent attempt. + /// If payment was attempted on this invoice but failed, this will be the time + /// of the most recent attempt. /// - public required System::DateTime? PaymentFailedAt + public required System::DateTimeOffset? PaymentFailedAt { get { - if (!this.Properties.TryGetValue("payment_failed_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_failed_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_failed_at"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "payment_failed_at" + ); } + init { JsonModel.Set(this._rawData, "payment_failed_at", value); } } /// - /// If payment was attempted on this invoice, this will be the start time of the - /// most recent attempt. This field is especially useful for delayed-notification + /// If payment was attempted on this invoice, this will be the start time of + /// the most recent attempt. This field is especially useful for delayed-notification /// payment mechanisms (like bank transfers), where payment can take 3 days or more. /// - public required System::DateTime? PaymentStartedAt + public required System::DateTimeOffset? PaymentStartedAt { get { - if (!this.Properties.TryGetValue("payment_started_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_started_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_started_at"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "payment_started_at" + ); } + init { JsonModel.Set(this._rawData, "payment_started_at", value); } } /// /// If the invoice is in draft, this timestamp will reflect when the invoice is /// scheduled to be issued. /// - public required System::DateTime? ScheduledIssueAt + public required System::DateTimeOffset? ScheduledIssueAt { get { - if (!this.Properties.TryGetValue("scheduled_issue_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "scheduled_issue_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["scheduled_issue_at"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "scheduled_issue_at" + ); } + init { JsonModel.Set(this._rawData, "scheduled_issue_at", value); } } public required Address? ShippingAddress { - get - { - if (!this.Properties.TryGetValue("shipping_address", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "shipping_address", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["shipping_address"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass
(this.RawData, "shipping_address"); } + init { JsonModel.Set(this._rawData, "shipping_address", value); } } - public required InvoiceProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } public required SubscriptionMinified? Subscription { get { - if (!this.Properties.TryGetValue("subscription", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "subscription"); } - set { this.Properties["subscription"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "subscription", value); } } /// @@ -801,18 +512,8 @@ public required SubscriptionMinified? Subscription /// public required string Subtotal { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } } /// @@ -820,19 +521,16 @@ public required string Subtotal /// provider sync was attempted. This field will always be `null` for invoices /// using Orb Invoicing. /// - public required System::DateTime? SyncFailedAt + public required System::DateTimeOffset? SyncFailedAt { get { - if (!this.Properties.TryGetValue("sync_failed_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "sync_failed_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawData, + "sync_failed_at" + ); } - set { this.Properties["sync_failed_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "sync_failed_at", value); } } /// @@ -840,34 +538,21 @@ public required string Subtotal /// public required string Total { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } } /// /// If the invoice has a status of `void`, this gives a timestamp when the invoice /// was voided. /// - public required System::DateTime? VoidedAt + public required System::DateTimeOffset? VoidedAt { get { - if (!this.Properties.TryGetValue("voided_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); } - set { this.Properties["voided_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "voided_at", value); } } /// @@ -876,19 +561,11 @@ public required string Total /// public required bool WillAutoIssue { - get - { - if (!this.Properties.TryGetValue("will_auto_issue", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "will_auto_issue", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["will_auto_issue"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "will_auto_issue"); } + init { JsonModel.Set(this._rawData, "will_auto_issue", value); } } + /// public override void Validate() { _ = this.ID; @@ -928,10 +605,7 @@ public override void Validate() this.Maximum?.Validate(); _ = this.MaximumAmount; _ = this.Memo; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; this.Minimum?.Validate(); _ = this.MinimumAmount; _ = this.PaidAt; @@ -952,20 +626,1937 @@ public override void Validate() _ = this.WillAutoIssue; } + [System::Obsolete("Required properties are deprecated: discount")] public Invoice() { } + [System::Obsolete("Required properties are deprecated: discount")] + public Invoice(Invoice invoice) + : base(invoice) { } + + [System::Obsolete("Required properties are deprecated: discount")] + public Invoice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [System::Obsolete("Required properties are deprecated: discount")] + [SetsRequiredMembers] + Invoice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Invoice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceFromRaw : IFromRawJson +{ + /// + public Invoice FromRawUnchecked(IReadOnlyDictionary rawData) => + Invoice.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceAutoCollection : JsonModel +{ + /// + /// True only if auto-collection is enabled for this invoice. + /// + public required bool? Enabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "enabled"); } + init { JsonModel.Set(this._rawData, "enabled", value); } + } + + /// + /// If the invoice is scheduled for auto-collection, this field will reflect when + /// the next attempt will occur. If dunning has been exhausted, or auto-collection + /// is not enabled for this invoice, this field will be `null`. + /// + public required System::DateTimeOffset? NextAttemptAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "next_attempt_at" + ); + } + init { JsonModel.Set(this._rawData, "next_attempt_at", value); } + } + + /// + /// Number of auto-collection payment attempts. + /// + public required long? NumAttempts + { + get { return JsonModel.GetNullableStruct(this.RawData, "num_attempts"); } + init { JsonModel.Set(this._rawData, "num_attempts", value); } + } + + /// + /// If Orb has ever attempted payment auto-collection for this invoice, this field + /// will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + /// this can be used to tell whether the invoice is currently in dunning (that + /// is, `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), + /// or if dunning has been exhausted (`previously_attempted_at` is non-null, but + /// `next_attempt_time` is null). + /// + public required System::DateTimeOffset? PreviouslyAttemptedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "previously_attempted_at" + ); + } + init { JsonModel.Set(this._rawData, "previously_attempted_at", value); } + } + + /// + public override void Validate() + { + _ = this.Enabled; + _ = this.NextAttemptAt; + _ = this.NumAttempts; + _ = this.PreviouslyAttemptedAt; + } + + public InvoiceAutoCollection() { } + + public InvoiceAutoCollection(InvoiceAutoCollection invoiceAutoCollection) + : base(invoiceAutoCollection) { } + + public InvoiceAutoCollection(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Invoice(Generic::Dictionary properties) + [SetsRequiredMembers] + InvoiceAutoCollection(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Invoice FromRawUnchecked( - Generic::Dictionary properties + /// + public static InvoiceAutoCollection FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceAutoCollectionFromRaw : IFromRawJson +{ + /// + public InvoiceAutoCollection FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoiceAutoCollection.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceCreditNote : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string CreditNoteNumber + { + get { return JsonModel.GetNotNullClass(this.RawData, "credit_note_number"); } + init { JsonModel.Set(this._rawData, "credit_note_number", value); } + } + + /// + /// An optional memo supplied on the credit note. + /// + public required string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + public required string Reason + { + get { return JsonModel.GetNotNullClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + public required string Total + { + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } + } + + public required string Type + { + get { return JsonModel.GetNotNullClass(this.RawData, "type"); } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + /// If the credit note has a status of `void`, this gives a timestamp when the + /// credit note was voided. + /// + public required System::DateTimeOffset? VoidedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); + } + init { JsonModel.Set(this._rawData, "voided_at", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CreditNoteNumber; + _ = this.Memo; + _ = this.Reason; + _ = this.Total; + _ = this.Type; + _ = this.VoidedAt; + } + + public InvoiceCreditNote() { } + + public InvoiceCreditNote(InvoiceCreditNote invoiceCreditNote) + : base(invoiceCreditNote) { } + + public InvoiceCreditNote(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceCreditNote(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceCreditNote FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceCreditNoteFromRaw : IFromRawJson +{ + /// + public InvoiceCreditNote FromRawUnchecked(IReadOnlyDictionary rawData) => + InvoiceCreditNote.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + InvoiceCustomerBalanceTransaction, + InvoiceCustomerBalanceTransactionFromRaw + >) +)] +public sealed record class InvoiceCustomerBalanceTransaction : JsonModel +{ + /// + /// A unique id for this transaction. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required ApiEnum Action + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "action"); + } + init { JsonModel.Set(this._rawData, "action", value); } + } + + /// + /// The value of the amount changed in the transaction. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The creation time of this transaction. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required CreditNoteTiny? CreditNote + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_note"); } + init { JsonModel.Set(this._rawData, "credit_note", value); } + } + + /// + /// An optional description provided for manual customer balance adjustments. + /// + public required string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// The new value of the customer's balance prior to the transaction, in the customer's currency. + /// + public required string EndingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } + } + + public required InvoiceTiny? Invoice + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice"); } + init { JsonModel.Set(this._rawData, "invoice", value); } + } + + /// + /// The original value of the customer's balance prior to the transaction, in + /// the customer's currency. + /// + public required string StartingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } + } + + public required ApiEnum Type + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "type"); + } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.Action.Validate(); + _ = this.Amount; + _ = this.CreatedAt; + this.CreditNote?.Validate(); + _ = this.Description; + _ = this.EndingBalance; + this.Invoice?.Validate(); + _ = this.StartingBalance; + this.Type.Validate(); + } + + public InvoiceCustomerBalanceTransaction() { } + + public InvoiceCustomerBalanceTransaction( + InvoiceCustomerBalanceTransaction invoiceCustomerBalanceTransaction + ) + : base(invoiceCustomerBalanceTransaction) { } + + public InvoiceCustomerBalanceTransaction(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceCustomerBalanceTransaction(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceCustomerBalanceTransaction FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceCustomerBalanceTransactionFromRaw : IFromRawJson +{ + /// + public InvoiceCustomerBalanceTransaction FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoiceCustomerBalanceTransaction.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(InvoiceCustomerBalanceTransactionActionConverter))] +public enum InvoiceCustomerBalanceTransactionAction +{ + AppliedToInvoice, + ManualAdjustment, + ProratedRefund, + RevertProratedRefund, + ReturnFromVoiding, + CreditNoteApplied, + CreditNoteVoided, + OverpaymentRefund, + ExternalPayment, + SmallInvoiceCarryover, +} + +sealed class InvoiceCustomerBalanceTransactionActionConverter + : JsonConverter +{ + public override InvoiceCustomerBalanceTransactionAction Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "applied_to_invoice" => InvoiceCustomerBalanceTransactionAction.AppliedToInvoice, + "manual_adjustment" => InvoiceCustomerBalanceTransactionAction.ManualAdjustment, + "prorated_refund" => InvoiceCustomerBalanceTransactionAction.ProratedRefund, + "revert_prorated_refund" => + InvoiceCustomerBalanceTransactionAction.RevertProratedRefund, + "return_from_voiding" => InvoiceCustomerBalanceTransactionAction.ReturnFromVoiding, + "credit_note_applied" => InvoiceCustomerBalanceTransactionAction.CreditNoteApplied, + "credit_note_voided" => InvoiceCustomerBalanceTransactionAction.CreditNoteVoided, + "overpayment_refund" => InvoiceCustomerBalanceTransactionAction.OverpaymentRefund, + "external_payment" => InvoiceCustomerBalanceTransactionAction.ExternalPayment, + "small_invoice_carryover" => + InvoiceCustomerBalanceTransactionAction.SmallInvoiceCarryover, + _ => (InvoiceCustomerBalanceTransactionAction)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceCustomerBalanceTransactionAction value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + InvoiceCustomerBalanceTransactionAction.AppliedToInvoice => "applied_to_invoice", + InvoiceCustomerBalanceTransactionAction.ManualAdjustment => "manual_adjustment", + InvoiceCustomerBalanceTransactionAction.ProratedRefund => "prorated_refund", + InvoiceCustomerBalanceTransactionAction.RevertProratedRefund => + "revert_prorated_refund", + InvoiceCustomerBalanceTransactionAction.ReturnFromVoiding => "return_from_voiding", + InvoiceCustomerBalanceTransactionAction.CreditNoteApplied => "credit_note_applied", + InvoiceCustomerBalanceTransactionAction.CreditNoteVoided => "credit_note_voided", + InvoiceCustomerBalanceTransactionAction.OverpaymentRefund => "overpayment_refund", + InvoiceCustomerBalanceTransactionAction.ExternalPayment => "external_payment", + InvoiceCustomerBalanceTransactionAction.SmallInvoiceCarryover => + "small_invoice_carryover", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(InvoiceCustomerBalanceTransactionTypeConverter))] +public enum InvoiceCustomerBalanceTransactionType +{ + Increment, + Decrement, +} + +sealed class InvoiceCustomerBalanceTransactionTypeConverter + : JsonConverter +{ + public override InvoiceCustomerBalanceTransactionType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => InvoiceCustomerBalanceTransactionType.Increment, + "decrement" => InvoiceCustomerBalanceTransactionType.Decrement, + _ => (InvoiceCustomerBalanceTransactionType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceCustomerBalanceTransactionType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + InvoiceCustomerBalanceTransactionType.Increment => "increment", + InvoiceCustomerBalanceTransactionType.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(InvoiceInvoiceSourceConverter))] +public enum InvoiceInvoiceSource +{ + Subscription, + Partial, + OneOff, +} + +sealed class InvoiceInvoiceSourceConverter : JsonConverter +{ + public override InvoiceInvoiceSource Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "subscription" => InvoiceInvoiceSource.Subscription, + "partial" => InvoiceInvoiceSource.Partial, + "one_off" => InvoiceInvoiceSource.OneOff, + _ => (InvoiceInvoiceSource)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceInvoiceSource value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + InvoiceInvoiceSource.Subscription => "subscription", + InvoiceInvoiceSource.Partial => "partial", + InvoiceInvoiceSource.OneOff => "one_off", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceLineItem : JsonModel +{ + /// + /// A unique ID for this line item. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The line amount after any adjustments and before overage conversion, credits + /// and partial invoicing. + /// + public required string AdjustedSubtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjusted_subtotal"); } + init { JsonModel.Set(this._rawData, "adjusted_subtotal", value); } + } + + /// + /// All adjustments applied to the line item in the order they were applied based + /// on invoice calculations (ie. usage discounts -> amount discounts -> percentage + /// discounts -> minimums -> maximums). + /// + public required IReadOnlyList Adjustments + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustments" + ); + } + init { JsonModel.Set(this._rawData, "adjustments", value); } + } + + /// + /// The final amount for a line item after all adjustments and pre paid credits + /// have been applied. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The number of prepaid credits applied. + /// + public required string CreditsApplied + { + get { return JsonModel.GetNotNullClass(this.RawData, "credits_applied"); } + init { JsonModel.Set(this._rawData, "credits_applied", value); } + } + + /// + /// The end date of the range of time applied for this line item's price. + /// + public required System::DateTimeOffset EndDate + { + get { return JsonModel.GetNotNullStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// An additional filter that was used to calculate the usage for this line item. + /// + public required string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// [DEPRECATED] For configured prices that are split by a grouping key, this + /// will be populated with the key and a value. The `amount` and `subtotal` will + /// be the values for this particular grouping. + /// + public required string? Grouping + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } + } + + /// + /// The name of the price associated with this line item. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Any amount applied from a partial invoice + /// + public required string PartiallyInvoicedAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "partially_invoiced_amount"); } + init { JsonModel.Set(this._rawData, "partially_invoiced_amount", value); } + } + + /// + /// The Price resource represents a price that can be billed on a subscription, + /// resulting in a charge on an invoice in the form of an invoice line item. + /// Prices take a quantity and determine an amount to bill. + /// + /// Orb supports a few different pricing models out of the box. Each of + /// these models is serialized differently in a given Price object. The model_type + /// field determines the key for the configuration object that is present. + /// + /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + /// + public required Price Price + { + get { return JsonModel.GetNotNullClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// Either the fixed fee quantity or the usage during the service period. + /// + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + /// The start date of the range of time applied for this line item's price. + /// + public required System::DateTimeOffset StartDate + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); + } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + /// For complex pricing structures, the line item can be broken down further + /// in `sub_line_items`. + /// + public required IReadOnlyList SubLineItems + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "sub_line_items" + ); + } + init { JsonModel.Set(this._rawData, "sub_line_items", value); } + } + + /// + /// The line amount before any adjustments. + /// + public required string Subtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } + + /// + /// An array of tax rates and their incurred tax amounts. Empty if no tax integration + /// is configured. + /// + public required IReadOnlyList TaxAmounts + { + get { return JsonModel.GetNotNullClass>(this.RawData, "tax_amounts"); } + init { JsonModel.Set(this._rawData, "tax_amounts", value); } + } + + /// + /// A list of customer ids that were used to calculate the usage for this line item. + /// + public required IReadOnlyList? UsageCustomerIDs + { + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.AdjustedSubtotal; + foreach (var item in this.Adjustments) + { + item.Validate(); + } + _ = this.Amount; + _ = this.CreditsApplied; + _ = this.EndDate; + _ = this.Filter; + _ = this.Grouping; + _ = this.Name; + _ = this.PartiallyInvoicedAmount; + this.Price.Validate(); + _ = this.Quantity; + _ = this.StartDate; + foreach (var item in this.SubLineItems) + { + item.Validate(); + } + _ = this.Subtotal; + foreach (var item in this.TaxAmounts) + { + item.Validate(); + } + _ = this.UsageCustomerIDs; + } + + public InvoiceLineItem() { } + + public InvoiceLineItem(InvoiceLineItem invoiceLineItem) + : base(invoiceLineItem) { } + + public InvoiceLineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceLineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceLineItem FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceLineItemFromRaw : IFromRawJson +{ + /// + public InvoiceLineItem FromRawUnchecked(IReadOnlyDictionary rawData) => + InvoiceLineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(InvoiceLineItemAdjustmentConverter))] +public record class InvoiceLineItemAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ID, + monetaryAmountDiscount: (x) => x.ID, + monetaryPercentageDiscount: (x) => x.ID, + monetaryMinimum: (x) => x.ID, + monetaryMaximum: (x) => x.ID + ); + } + } + + public string Amount + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.Amount, + monetaryAmountDiscount: (x) => x.Amount, + monetaryPercentageDiscount: (x) => x.Amount, + monetaryMinimum: (x) => x.Amount, + monetaryMaximum: (x) => x.Amount + ); + } + } + + public bool IsInvoiceLevel + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.IsInvoiceLevel, + monetaryAmountDiscount: (x) => x.IsInvoiceLevel, + monetaryPercentageDiscount: (x) => x.IsInvoiceLevel, + monetaryMinimum: (x) => x.IsInvoiceLevel, + monetaryMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public string? Reason + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.Reason, + monetaryAmountDiscount: (x) => x.Reason, + monetaryPercentageDiscount: (x) => x.Reason, + monetaryMinimum: (x) => x.Reason, + monetaryMaximum: (x) => x.Reason + ); + } + } + + public string? ReplacesAdjustmentID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryAmountDiscount: (x) => x.ReplacesAdjustmentID, + monetaryPercentageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryMinimum: (x) => x.ReplacesAdjustmentID, + monetaryMaximum: (x) => x.ReplacesAdjustmentID + ); + } + } + + public InvoiceLineItemAdjustment( + MonetaryUsageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemAdjustment( + MonetaryAmountDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemAdjustment( + MonetaryPercentageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemAdjustment(MonetaryMinimumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemAdjustment(MonetaryMaximumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryUsageDiscount(out var value)) { + /// // `value` is of type `MonetaryUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryUsageDiscount( + [NotNullWhen(true)] out MonetaryUsageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryUsageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryAmountDiscount(out var value)) { + /// // `value` is of type `MonetaryAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryAmountDiscount( + [NotNullWhen(true)] out MonetaryAmountDiscountAdjustment? value + ) + { + value = this.Value as MonetaryAmountDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryPercentageDiscount(out var value)) { + /// // `value` is of type `MonetaryPercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryPercentageDiscount( + [NotNullWhen(true)] out MonetaryPercentageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryPercentageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMinimum(out var value)) { + /// // `value` is of type `MonetaryMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMinimum([NotNullWhen(true)] out MonetaryMinimumAdjustment? value) + { + value = this.Value as MonetaryMinimumAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMaximum(out var value)) { + /// // `value` is of type `MonetaryMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMaximum([NotNullWhen(true)] out MonetaryMaximumAdjustment? value) + { + value = this.Value as MonetaryMaximumAdjustment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action monetaryUsageDiscount, + System::Action monetaryAmountDiscount, + System::Action monetaryPercentageDiscount, + System::Action monetaryMinimum, + System::Action monetaryMaximum + ) + { + switch (this.Value) + { + case MonetaryUsageDiscountAdjustment value: + monetaryUsageDiscount(value); + break; + case MonetaryAmountDiscountAdjustment value: + monetaryAmountDiscount(value); + break; + case MonetaryPercentageDiscountAdjustment value: + monetaryPercentageDiscount(value); + break; + case MonetaryMinimumAdjustment value: + monetaryMinimum(value); + break; + case MonetaryMaximumAdjustment value: + monetaryMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLineItemAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func monetaryUsageDiscount, + System::Func monetaryAmountDiscount, + System::Func monetaryPercentageDiscount, + System::Func monetaryMinimum, + System::Func monetaryMaximum + ) + { + return this.Value switch + { + MonetaryUsageDiscountAdjustment value => monetaryUsageDiscount(value), + MonetaryAmountDiscountAdjustment value => monetaryAmountDiscount(value), + MonetaryPercentageDiscountAdjustment value => monetaryPercentageDiscount(value), + MonetaryMinimumAdjustment value => monetaryMinimum(value), + MonetaryMaximumAdjustment value => monetaryMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLineItemAdjustment" + ), + }; + } + + public static implicit operator InvoiceLineItemAdjustment( + MonetaryUsageDiscountAdjustment value + ) => new(value); + + public static implicit operator InvoiceLineItemAdjustment( + MonetaryAmountDiscountAdjustment value + ) => new(value); + + public static implicit operator InvoiceLineItemAdjustment( + MonetaryPercentageDiscountAdjustment value + ) => new(value); + + public static implicit operator InvoiceLineItemAdjustment(MonetaryMinimumAdjustment value) => + new(value); + + public static implicit operator InvoiceLineItemAdjustment(MonetaryMaximumAdjustment value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLineItemAdjustment" + ); + } + this.Switch( + (monetaryUsageDiscount) => monetaryUsageDiscount.Validate(), + (monetaryAmountDiscount) => monetaryAmountDiscount.Validate(), + (monetaryPercentageDiscount) => monetaryPercentageDiscount.Validate(), + (monetaryMinimum) => monetaryMinimum.Validate(), + (monetaryMaximum) => monetaryMaximum.Validate() + ); + } + + public virtual bool Equals(InvoiceLineItemAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class InvoiceLineItemAdjustmentConverter : JsonConverter +{ + public override InvoiceLineItemAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new InvoiceLineItemAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceLineItemAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(InvoiceLineItemSubLineItemConverter))] +public record class InvoiceLineItemSubLineItem +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Amount + { + get + { + return Match(matrix: (x) => x.Amount, tier: (x) => x.Amount, other: (x) => x.Amount); + } + } + + public SubLineItemGrouping? Grouping + { + get + { + return Match( + matrix: (x) => x.Grouping, + tier: (x) => x.Grouping, + other: (x) => x.Grouping + ); + } + } + + public string Name + { + get { return Match(matrix: (x) => x.Name, tier: (x) => x.Name, other: (x) => x.Name); } + } + + public double Quantity + { + get + { + return Match( + matrix: (x) => x.Quantity, + tier: (x) => x.Quantity, + other: (x) => x.Quantity + ); + } + } + + public InvoiceLineItemSubLineItem(MatrixSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemSubLineItem(TierSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemSubLineItem(OtherSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLineItemSubLineItem(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrix(out var value)) { + /// // `value` is of type `MatrixSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrix([NotNullWhen(true)] out MatrixSubLineItem? value) + { + value = this.Value as MatrixSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTier(out var value)) { + /// // `value` is of type `TierSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTier([NotNullWhen(true)] out TierSubLineItem? value) + { + value = this.Value as TierSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickOther(out var value)) { + /// // `value` is of type `OtherSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickOther([NotNullWhen(true)] out OtherSubLineItem? value) + { + value = this.Value as OtherSubLineItem; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action matrix, + System::Action tier, + System::Action other + ) + { + switch (this.Value) + { + case MatrixSubLineItem value: + matrix(value); + break; + case TierSubLineItem value: + tier(value); + break; + case OtherSubLineItem value: + other(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLineItemSubLineItem" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func matrix, + System::Func tier, + System::Func other + ) + { + return this.Value switch + { + MatrixSubLineItem value => matrix(value), + TierSubLineItem value => tier(value), + OtherSubLineItem value => other(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLineItemSubLineItem" + ), + }; + } + + public static implicit operator InvoiceLineItemSubLineItem(MatrixSubLineItem value) => + new(value); + + public static implicit operator InvoiceLineItemSubLineItem(TierSubLineItem value) => new(value); + + public static implicit operator InvoiceLineItemSubLineItem(OtherSubLineItem value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLineItemSubLineItem" + ); + } + this.Switch( + (matrix) => matrix.Validate(), + (tier) => tier.Validate(), + (other) => other.Validate() + ); + } + + public virtual bool Equals(InvoiceLineItemSubLineItem? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class InvoiceLineItemSubLineItemConverter : JsonConverter +{ + public override InvoiceLineItemSubLineItem? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? type; + try + { + type = element.GetProperty("type").GetString(); + } + catch + { + type = null; + } + + switch (type) + { + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tier": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "'null'": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new InvoiceLineItemSubLineItem(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceLineItemSubLineItem value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoicePaymentAttempt : JsonModel +{ + /// + /// The ID of the payment attempt. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The amount of the payment attempt. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The time at which the payment attempt was created. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + /// + /// The payment provider that attempted to collect the payment. + /// + public required ApiEnum? PaymentProvider + { + get + { + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "payment_provider"); + } + init { JsonModel.Set(this._rawData, "payment_provider", value); } + } + + /// + /// The ID of the payment attempt in the payment provider. + /// + public required string? PaymentProviderID + { + get { return JsonModel.GetNullableClass(this.RawData, "payment_provider_id"); } + init { JsonModel.Set(this._rawData, "payment_provider_id", value); } + } + + /// + /// URL to the downloadable PDF version of the receipt. This field will be `null` + /// for payment attempts that did not succeed. + /// + public required string? ReceiptPdf + { + get { return JsonModel.GetNullableClass(this.RawData, "receipt_pdf"); } + init { JsonModel.Set(this._rawData, "receipt_pdf", value); } + } + + /// + /// Whether the payment attempt succeeded. + /// + public required bool Succeeded + { + get { return JsonModel.GetNotNullStruct(this.RawData, "succeeded"); } + init { JsonModel.Set(this._rawData, "succeeded", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Amount; + _ = this.CreatedAt; + this.PaymentProvider?.Validate(); + _ = this.PaymentProviderID; + _ = this.ReceiptPdf; + _ = this.Succeeded; + } + + public InvoicePaymentAttempt() { } + + public InvoicePaymentAttempt(InvoicePaymentAttempt invoicePaymentAttempt) + : base(invoicePaymentAttempt) { } + + public InvoicePaymentAttempt(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoicePaymentAttempt(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoicePaymentAttempt FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoicePaymentAttemptFromRaw : IFromRawJson +{ + /// + public InvoicePaymentAttempt FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoicePaymentAttempt.FromRawUnchecked(rawData); +} + +/// +/// The payment provider that attempted to collect the payment. +/// +[JsonConverter(typeof(InvoicePaymentAttemptPaymentProviderConverter))] +public enum InvoicePaymentAttemptPaymentProvider +{ + Stripe, +} + +sealed class InvoicePaymentAttemptPaymentProviderConverter + : JsonConverter +{ + public override InvoicePaymentAttemptPaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => InvoicePaymentAttemptPaymentProvider.Stripe, + _ => (InvoicePaymentAttemptPaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoicePaymentAttemptPaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + InvoicePaymentAttemptPaymentProvider.Stripe => "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(InvoiceStatusConverter))] +public enum InvoiceStatus +{ + Issued, + Paid, + Synced, + Void, + Draft, +} + +sealed class InvoiceStatusConverter : JsonConverter +{ + public override InvoiceStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "issued" => InvoiceStatus.Issued, + "paid" => InvoiceStatus.Paid, + "synced" => InvoiceStatus.Synced, + "void" => InvoiceStatus.Void, + "draft" => InvoiceStatus.Draft, + _ => (InvoiceStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + InvoiceStatus.Issued => "issued", + InvoiceStatus.Paid => "paid", + InvoiceStatus.Synced => "synced", + InvoiceStatus.Void => "void", + InvoiceStatus.Draft => "draft", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/InvoiceLevelDiscount.cs b/src/Orb/Models/InvoiceLevelDiscount.cs index 849a5121..6dd9086f 100644 --- a/src/Orb/Models/InvoiceLevelDiscount.cs +++ b/src/Orb/Models/InvoiceLevelDiscount.cs @@ -1,23 +1,341 @@ -using InvoiceLevelDiscountVariants = Orb.Models.InvoiceLevelDiscountVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; +using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class InvoiceLevelDiscount +[JsonConverter(typeof(InvoiceLevelDiscountConverter))] +public record class InvoiceLevelDiscount { - internal InvoiceLevelDiscount() { } + public object? Value { get; } = null; - public static InvoiceLevelDiscountVariants::PercentageDiscount Create( - PercentageDiscount value - ) => new(value); + JsonElement? _element = null; - public static InvoiceLevelDiscountVariants::AmountDiscount Create(AmountDiscount value) => - new(value); + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } - public static InvoiceLevelDiscountVariants::TrialDiscount Create(TrialDiscount value) => - new(value); + public string? Reason + { + get + { + return Match( + percentage: (x) => x.Reason, + amount: (x) => x.Reason, + trial: (x) => x.Reason + ); + } + } - public abstract void Validate(); + public InvoiceLevelDiscount(PercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLevelDiscount(AmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLevelDiscount(TrialDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceLevelDiscount(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `PercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out PercentageDiscount? value) + { + value = this.Value as PercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `AmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out AmountDiscount? value) + { + value = this.Value as AmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTrial(out var value)) { + /// // `value` is of type `TrialDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTrial([NotNullWhen(true)] out TrialDiscount? value) + { + value = this.Value as TrialDiscount; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (PercentageDiscount value) => {...}, + /// (AmountDiscount value) => {...}, + /// (TrialDiscount value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action percentage, + System::Action amount, + System::Action trial + ) + { + switch (this.Value) + { + case PercentageDiscount value: + percentage(value); + break; + case AmountDiscount value: + amount(value); + break; + case TrialDiscount value: + trial(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLevelDiscount" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (PercentageDiscount value) => {...}, + /// (AmountDiscount value) => {...}, + /// (TrialDiscount value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func percentage, + System::Func amount, + System::Func trial + ) + { + return this.Value switch + { + PercentageDiscount value => percentage(value), + AmountDiscount value => amount(value), + TrialDiscount value => trial(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLevelDiscount" + ), + }; + } + + public static implicit operator InvoiceLevelDiscount(PercentageDiscount value) => new(value); + + public static implicit operator InvoiceLevelDiscount(AmountDiscount value) => new(value); + + public static implicit operator InvoiceLevelDiscount(TrialDiscount value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceLevelDiscount" + ); + } + this.Switch( + (percentage) => percentage.Validate(), + (amount) => amount.Validate(), + (trial) => trial.Validate() + ); + } + + public virtual bool Equals(InvoiceLevelDiscount? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class InvoiceLevelDiscountConverter : JsonConverter +{ + public override InvoiceLevelDiscount? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); + } + catch + { + discountType = null; + } + + switch (discountType) + { + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "trial": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new InvoiceLevelDiscount(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceLevelDiscount value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/InvoiceLevelDiscountVariants/All.cs b/src/Orb/Models/InvoiceLevelDiscountVariants/All.cs deleted file mode 100644 index 79f191ce..00000000 --- a/src/Orb/Models/InvoiceLevelDiscountVariants/All.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceLevelDiscountVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PercentageDiscount(Models::PercentageDiscount Value) - : Models::InvoiceLevelDiscount, - Orb::IVariant -{ - public static PercentageDiscount From(Models::PercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmountDiscount(Models::AmountDiscount Value) - : Models::InvoiceLevelDiscount, - Orb::IVariant -{ - public static AmountDiscount From(Models::AmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class TrialDiscount(Models::TrialDiscount Value) - : Models::InvoiceLevelDiscount, - Orb::IVariant -{ - public static TrialDiscount From(Models::TrialDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateParams.cs b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateParams.cs index ecebe476..40d9867b 100644 --- a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateParams.cs +++ b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateParams.cs @@ -1,55 +1,51 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.InvoiceLineItems; /// /// This creates a one-off fixed fee invoice line item on an Invoice. This can only /// be done for invoices that are in a `draft` status. +/// +/// The behavior depends on which parameters are provided: - If `item_id` is +/// provided without `name`: The item is looked up by ID, and the item's name is +/// used for the line item. - If `name` is provided without `item_id`: An item with +/// the given name is searched for in the account. If found, that item is used. +/// If not found, a new item is created with that name. The new item's name is used +/// for the line item. - If both `item_id` and `name` are provided: The item is looked +/// up by ID for association, but the provided `name` is used for the line item +/// (not the item's name). /// -public sealed record class InvoiceLineItemCreateParams : Orb::ParamsBase +public sealed record class InvoiceLineItemCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// The total amount in the invoice's currency to add to the line item. /// public required string Amount { - get - { - if (!this.BodyProperties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.BodyProperties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "amount"); } + init { JsonModel.Set(this._rawBodyData, "amount", value); } } /// /// A date string to specify the line item's end date in the customer's timezone. /// - public required System::DateOnly EndDate + public required string EndDate { - get - { - if (!this.BodyProperties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "end_date"); } + init { JsonModel.Set(this._rawBodyData, "end_date", value); } } /// @@ -57,98 +53,124 @@ public required string Amount /// public required string InvoiceID { - get - { - if (!this.BodyProperties.TryGetValue("invoice_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_id"); - } - set { this.BodyProperties["invoice_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "invoice_id"); } + init { JsonModel.Set(this._rawBodyData, "invoice_id", value); } } /// - /// The item name associated with this line item. If an item with the same name - /// exists in Orb, that item will be associated with the line item. + /// The number of units on the line item /// - public required string Name + public required double Quantity { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "quantity"); } + init { JsonModel.Set(this._rawBodyData, "quantity", value); } } /// - /// The number of units on the line item + /// A date string to specify the line item's start date in the customer's timezone. /// - public required double Quantity + public required string StartDate { - get - { - if (!this.BodyProperties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); + get { return JsonModel.GetNotNullClass(this.RawBodyData, "start_date"); } + init { JsonModel.Set(this._rawBodyData, "start_date", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// The id of the item to associate with this line item. If provided without + /// `name`, the item's name will be used for the price/line item. If provided + /// with `name`, the item will be associated but `name` will be used for the line + /// item. At least one of `name` or `item_id` must be provided. + /// + public string? ItemID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "item_id"); } + init { JsonModel.Set(this._rawBodyData, "item_id", value); } } /// - /// A date string to specify the line item's start date in the customer's timezone. + /// The name to use for the line item. If `item_id` is not provided, Orb will + /// search for an item with this name. If found, that item will be associated + /// with the line item. If not found, a new item will be created with this name. + /// If `item_id` is provided, this name will be used for the line item, but the + /// item association will be based on `item_id`. At least one of `name` or `item_id` + /// must be provided. /// - public required System::DateOnly StartDate + public string? Name { - get - { - if (!this.BodyProperties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); + get { return JsonModel.GetNullableClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + public InvoiceLineItemCreateParams() { } + + public InvoiceLineItemCreateParams(InvoiceLineItemCreateParams invoiceLineItemCreateParams) + : base(invoiceLineItemCreateParams) + { + this._rawBodyData = [.. invoiceLineItemCreateParams._rawBodyData]; + } + + public InvoiceLineItemCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceLineItemCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceLineItemCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + "/invoice_line_items" - ) + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/invoice_line_items") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponse.cs b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponse.cs index b22001a7..bfd7751d 100644 --- a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponse.cs +++ b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponse.cs @@ -1,33 +1,26 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using InvoiceLineItemCreateResponseProperties = Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.InvoiceLineItems; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceLineItemCreateResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class InvoiceLineItemCreateResponse : JsonModel { /// /// A unique ID for this line item. /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -36,21 +29,8 @@ public required string ID /// public required string AdjustedSubtotal { - get - { - if (!this.Properties.TryGetValue("adjusted_subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjusted_subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjusted_subtotal"); - } - set - { - this.Properties["adjusted_subtotal"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "adjusted_subtotal"); } + init { JsonModel.Set(this._rawData, "adjusted_subtotal", value); } } /// @@ -58,21 +38,16 @@ public required string AdjustedSubtotal /// on invoice calculations (ie. usage discounts -> amount discounts -> percentage /// discounts -> minimums -> maximums). /// - public required Generic::List Adjustments + public required IReadOnlyList Adjustments { get { - if (!this.Properties.TryGetValue("adjustments", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustments", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustments"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustments" + ); } - set { this.Properties["adjustments"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustments", value); } } /// @@ -81,18 +56,8 @@ public required string AdjustedSubtotal /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// @@ -100,403 +65,1097 @@ public required string Amount /// public required string CreditsApplied { - get - { - if (!this.Properties.TryGetValue("credits_applied", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credits_applied", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credits_applied"); - } - set { this.Properties["credits_applied"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "credits_applied"); } + init { JsonModel.Set(this._rawData, "credits_applied", value); } } /// - /// This field is deprecated in favor of `adjustments` + /// The end date of the range of time applied for this line item's price. /// - public required Models::Discount? Discount + public required System::DateTimeOffset EndDate { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// - /// The end date of the range of time applied for this line item's price. + /// An additional filter that was used to calculate the usage for this line item. /// - public required System::DateTime EndDate + public required string? Filter { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// [DEPRECATED] For configured prices that are split by a grouping key, this + /// will be populated with the key and a value. The `amount` and `subtotal` will + /// be the values for this particular grouping. + /// + public required string? Grouping + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } } /// - /// An additional filter that was used to calculate the usage for this line item. + /// The name of the price associated with this line item. /// - public required string? Filter + public required string Name { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filter", - "Missing required argument" - ); + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Any amount applied from a partial invoice + /// + public required string PartiallyInvoicedAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "partially_invoiced_amount"); } + init { JsonModel.Set(this._rawData, "partially_invoiced_amount", value); } } /// - /// [DEPRECATED] For configured prices that are split by a grouping key, this will - /// be populated with the key and a value. The `amount` and `subtotal` will be - /// the values for this particular grouping. + /// The Price resource represents a price that can be billed on a subscription, + /// resulting in a charge on an invoice in the form of an invoice line item. + /// Prices take a quantity and determine an amount to bill. + /// + /// Orb supports a few different pricing models out of the box. Each of + /// these models is serialized differently in a given Price object. The model_type + /// field determines the key for the configuration object that is present. + /// + /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) /// - public required string? Grouping + public required Price Price { - get - { - if (!this.Properties.TryGetValue("grouping", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping", - "Missing required argument" - ); + get { return JsonModel.GetNotNullClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["grouping"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Either the fixed fee quantity or the usage during the service period. + /// + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } /// - /// This field is deprecated in favor of `adjustments`. + /// The start date of the range of time applied for this line item's price. /// - public required Models::Maximum? Maximum + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } /// - /// This field is deprecated in favor of `adjustments`. + /// For complex pricing structures, the line item can be broken down further + /// in `sub_line_items`. /// - public required string? MaximumAmount + public required IReadOnlyList SubLineItems { get { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullClass>( + this.RawData, + "sub_line_items" + ); } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "sub_line_items", value); } } /// - /// This field is deprecated in favor of `adjustments`. + /// The line amount before any adjustments. /// - public required Models::Minimum? Minimum + public required string Subtotal { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// An array of tax rates and their incurred tax amounts. Empty if no tax integration + /// is configured. + /// + public required IReadOnlyList TaxAmounts + { + get { return JsonModel.GetNotNullClass>(this.RawData, "tax_amounts"); } + init { JsonModel.Set(this._rawData, "tax_amounts", value); } } /// - /// This field is deprecated in favor of `adjustments`. + /// A list of customer ids that were used to calculate the usage for this line item. /// - public required string? MinimumAmount + public required IReadOnlyList? UsageCustomerIDs { - get + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.AdjustedSubtotal; + foreach (var item in this.Adjustments) + { + item.Validate(); + } + _ = this.Amount; + _ = this.CreditsApplied; + _ = this.EndDate; + _ = this.Filter; + _ = this.Grouping; + _ = this.Name; + _ = this.PartiallyInvoicedAmount; + this.Price.Validate(); + _ = this.Quantity; + _ = this.StartDate; + foreach (var item in this.SubLineItems) { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); + item.Validate(); + } + _ = this.Subtotal; + foreach (var item in this.TaxAmounts) + { + item.Validate(); + } + _ = this.UsageCustomerIDs; + } + + public InvoiceLineItemCreateResponse() { } + + public InvoiceLineItemCreateResponse( + InvoiceLineItemCreateResponse invoiceLineItemCreateResponse + ) + : base(invoiceLineItemCreateResponse) { } - return Json::JsonSerializer.Deserialize(element); + public InvoiceLineItemCreateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceLineItemCreateResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceLineItemCreateResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceLineItemCreateResponseFromRaw : IFromRawJson +{ + /// + public InvoiceLineItemCreateResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoiceLineItemCreateResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.InvoiceLineItems.AdjustmentConverter))] +public record class Adjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ID, + monetaryAmountDiscount: (x) => x.ID, + monetaryPercentageDiscount: (x) => x.ID, + monetaryMinimum: (x) => x.ID, + monetaryMaximum: (x) => x.ID + ); } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } } - /// - /// The name of the price associated with this line item. - /// - public required string Name + public string Amount { get { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); + return Match( + monetaryUsageDiscount: (x) => x.Amount, + monetaryAmountDiscount: (x) => x.Amount, + monetaryPercentageDiscount: (x) => x.Amount, + monetaryMinimum: (x) => x.Amount, + monetaryMaximum: (x) => x.Amount + ); + } + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); + public bool IsInvoiceLevel + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.IsInvoiceLevel, + monetaryAmountDiscount: (x) => x.IsInvoiceLevel, + monetaryPercentageDiscount: (x) => x.IsInvoiceLevel, + monetaryMinimum: (x) => x.IsInvoiceLevel, + monetaryMaximum: (x) => x.IsInvoiceLevel + ); } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } } - /// - /// Any amount applied from a partial invoice - /// - public required string PartiallyInvoicedAmount + public string? Reason { get { - if ( - !this.Properties.TryGetValue( - "partially_invoiced_amount", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "partially_invoiced_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("partially_invoiced_amount"); + return Match( + monetaryUsageDiscount: (x) => x.Reason, + monetaryAmountDiscount: (x) => x.Reason, + monetaryPercentageDiscount: (x) => x.Reason, + monetaryMinimum: (x) => x.Reason, + monetaryMaximum: (x) => x.Reason + ); } - set + } + + public string? ReplacesAdjustmentID + { + get { - this.Properties["partially_invoiced_amount"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + monetaryUsageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryAmountDiscount: (x) => x.ReplacesAdjustmentID, + monetaryPercentageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryMinimum: (x) => x.ReplacesAdjustmentID, + monetaryMaximum: (x) => x.ReplacesAdjustmentID ); } } + public Adjustment(MonetaryUsageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryAmountDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryPercentageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryMinimumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryMaximumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(JsonElement element) + { + this._element = element; + } + /// - /// The Price resource represents a price that can be billed on a subscription, - /// resulting in a charge on an invoice in the form of an invoice line item. Prices - /// take a quantity and determine an amount to bill. + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . /// - /// Orb supports a few different pricing models out of the box. Each of these models - /// is serialized differently in a given Price object. The model_type field determines - /// the key for the configuration object that is present. + /// Consider using or if you need to handle every variant. /// - /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + /// + /// + /// if (instance.TryPickMonetaryUsageDiscount(out var value)) { + /// // `value` is of type `MonetaryUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// /// - public required Models::Price Price + public bool TryPickMonetaryUsageDiscount( + [NotNullWhen(true)] out MonetaryUsageDiscountAdjustment? value + ) { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("price", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price"); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } + value = this.Value as MonetaryUsageDiscountAdjustment; + return value != null; } /// - /// Either the fixed fee quantity or the usage during the service period. + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryAmountDiscount(out var value)) { + /// // `value` is of type `MonetaryAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// /// - public required double Quantity + public bool TryPickMonetaryAmountDiscount( + [NotNullWhen(true)] out MonetaryAmountDiscountAdjustment? value + ) { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); + value = this.Value as MonetaryAmountDiscountAdjustment; + return value != null; + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryPercentageDiscount(out var value)) { + /// // `value` is of type `MonetaryPercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryPercentageDiscount( + [NotNullWhen(true)] out MonetaryPercentageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryPercentageDiscountAdjustment; + return value != null; } /// - /// The start date of the range of time applied for this line item's price. + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMinimum(out var value)) { + /// // `value` is of type `MonetaryMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// /// - public required System::DateTime StartDate + public bool TryPickMonetaryMinimum([NotNullWhen(true)] out MonetaryMinimumAdjustment? value) { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); + value = this.Value as MonetaryMinimumAdjustment; + return value != null; + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMaximum(out var value)) { + /// // `value` is of type `MonetaryMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMaximum([NotNullWhen(true)] out MonetaryMaximumAdjustment? value) + { + value = this.Value as MonetaryMaximumAdjustment; + return value != null; } /// - /// For complex pricing structures, the line item can be broken down further in `sub_line_items`. + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// /// - public required Generic::List SubLineItems + public void Switch( + System::Action monetaryUsageDiscount, + System::Action monetaryAmountDiscount, + System::Action monetaryPercentageDiscount, + System::Action monetaryMinimum, + System::Action monetaryMaximum + ) { - get + switch (this.Value) { - if (!this.Properties.TryGetValue("sub_line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "sub_line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("sub_line_items"); + case MonetaryUsageDiscountAdjustment value: + monetaryUsageDiscount(value); + break; + case MonetaryAmountDiscountAdjustment value: + monetaryAmountDiscount(value); + break; + case MonetaryPercentageDiscountAdjustment value: + monetaryPercentageDiscount(value); + break; + case MonetaryMinimumAdjustment value: + monetaryMinimum(value); + break; + case MonetaryMaximumAdjustment value: + monetaryMaximum(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); } - set { this.Properties["sub_line_items"] = Json::JsonSerializer.SerializeToElement(value); } } /// - /// The line amount before before any adjustments. + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// /// - public required string Subtotal + public T Match( + System::Func monetaryUsageDiscount, + System::Func monetaryAmountDiscount, + System::Func monetaryPercentageDiscount, + System::Func monetaryMinimum, + System::Func monetaryMaximum + ) { - get + return this.Value switch { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } + MonetaryUsageDiscountAdjustment value => monetaryUsageDiscount(value), + MonetaryAmountDiscountAdjustment value => monetaryAmountDiscount(value), + MonetaryPercentageDiscountAdjustment value => monetaryPercentageDiscount(value), + MonetaryMinimumAdjustment value => monetaryMinimum(value), + MonetaryMaximumAdjustment value => monetaryMaximum(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Adjustment"), + }; } + public static implicit operator global::Orb.Models.InvoiceLineItems.Adjustment( + MonetaryUsageDiscountAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.InvoiceLineItems.Adjustment( + MonetaryAmountDiscountAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.InvoiceLineItems.Adjustment( + MonetaryPercentageDiscountAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.InvoiceLineItems.Adjustment( + MonetaryMinimumAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.InvoiceLineItems.Adjustment( + MonetaryMaximumAdjustment value + ) => new(value); + /// - /// An array of tax rates and their incurred tax amounts. Empty if no tax integration - /// is configured. + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// /// - public required Generic::List TaxAmounts + public void Validate() { - get + if (this.Value == null) { - if (!this.Properties.TryGetValue("tax_amounts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_amounts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tax_amounts"); + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); } - set { this.Properties["tax_amounts"] = Json::JsonSerializer.SerializeToElement(value); } + this.Switch( + (monetaryUsageDiscount) => monetaryUsageDiscount.Validate(), + (monetaryAmountDiscount) => monetaryAmountDiscount.Validate(), + (monetaryPercentageDiscount) => monetaryPercentageDiscount.Validate(), + (monetaryMinimum) => monetaryMinimum.Validate(), + (monetaryMaximum) => monetaryMaximum.Validate() + ); } - /// - /// A list of customer ids that were used to calculate the usage for this line item. - /// - public required Generic::List? UsageCustomerIDs + public virtual bool Equals(global::Orb.Models.InvoiceLineItems.Adjustment? other) { - get + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentConverter : JsonConverter +{ + public override global::Orb.Models.InvoiceLineItems.Adjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) { - if (!this.Properties.TryGetValue("usage_customer_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_customer_ids", - "Missing required argument" - ); + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } - return Json::JsonSerializer.Deserialize?>(element); + return new(element); + } + default: + { + return new global::Orb.Models.InvoiceLineItems.Adjustment(element); + } } - set + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.InvoiceLineItems.Adjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(global::Orb.Models.InvoiceLineItems.SubLineItemConverter))] +public record class SubLineItem +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Amount + { + get { - this.Properties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); + return Match(matrix: (x) => x.Amount, tier: (x) => x.Amount, other: (x) => x.Amount); } } - public override void Validate() + public SubLineItemGrouping? Grouping { - _ = this.ID; - _ = this.AdjustedSubtotal; - foreach (var item in this.Adjustments) + get { - item.Validate(); + return Match( + matrix: (x) => x.Grouping, + tier: (x) => x.Grouping, + other: (x) => x.Grouping + ); } - _ = this.Amount; - _ = this.CreditsApplied; - this.Discount?.Validate(); - _ = this.EndDate; - _ = this.Filter; - _ = this.Grouping; - this.Maximum?.Validate(); - _ = this.MaximumAmount; - this.Minimum?.Validate(); - _ = this.MinimumAmount; - _ = this.Name; - _ = this.PartiallyInvoicedAmount; - this.Price.Validate(); - _ = this.Quantity; - _ = this.StartDate; - foreach (var item in this.SubLineItems) + } + + public string Name + { + get { return Match(matrix: (x) => x.Name, tier: (x) => x.Name, other: (x) => x.Name); } + } + + public double Quantity + { + get { - item.Validate(); + return Match( + matrix: (x) => x.Quantity, + tier: (x) => x.Quantity, + other: (x) => x.Quantity + ); } - _ = this.Subtotal; - foreach (var item in this.TaxAmounts) + } + + public SubLineItem(MatrixSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(TierSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(OtherSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrix(out var value)) { + /// // `value` is of type `MatrixSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrix([NotNullWhen(true)] out MatrixSubLineItem? value) + { + value = this.Value as MatrixSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTier(out var value)) { + /// // `value` is of type `TierSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTier([NotNullWhen(true)] out TierSubLineItem? value) + { + value = this.Value as TierSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickOther(out var value)) { + /// // `value` is of type `OtherSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickOther([NotNullWhen(true)] out OtherSubLineItem? value) + { + value = this.Value as OtherSubLineItem; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action matrix, + System::Action tier, + System::Action other + ) + { + switch (this.Value) { - item.Validate(); + case MatrixSubLineItem value: + matrix(value); + break; + case TierSubLineItem value: + tier(value); + break; + case OtherSubLineItem value: + other(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"); } - foreach (var item in this.UsageCustomerIDs ?? []) + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func matrix, + System::Func tier, + System::Func other + ) + { + return this.Value switch { - _ = item; + MatrixSubLineItem value => matrix(value), + TierSubLineItem value => tier(value), + OtherSubLineItem value => other(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"), + }; + } + + public static implicit operator global::Orb.Models.InvoiceLineItems.SubLineItem( + MatrixSubLineItem value + ) => new(value); + + public static implicit operator global::Orb.Models.InvoiceLineItems.SubLineItem( + TierSubLineItem value + ) => new(value); + + public static implicit operator global::Orb.Models.InvoiceLineItems.SubLineItem( + OtherSubLineItem value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"); } + this.Switch( + (matrix) => matrix.Validate(), + (tier) => tier.Validate(), + (other) => other.Validate() + ); } - public InvoiceLineItemCreateResponse() { } + public virtual bool Equals(global::Orb.Models.InvoiceLineItems.SubLineItem? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceLineItemCreateResponse(Generic::Dictionary properties) + public override int GetHashCode() { - Properties = properties; + return 0; } -#pragma warning restore CS8618 +} - public static InvoiceLineItemCreateResponse FromRawUnchecked( - Generic::Dictionary properties +sealed class SubLineItemConverter : JsonConverter +{ + public override global::Orb.Models.InvoiceLineItems.SubLineItem? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? type; + try + { + type = element.GetProperty("type").GetString(); + } + catch + { + type = null; + } + + switch (type) + { + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tier": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "'null'": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.InvoiceLineItems.SubLineItem(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.InvoiceLineItems.SubLineItem value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/Adjustment.cs b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/Adjustment.cs deleted file mode 100644 index 461f2f8a..00000000 --- a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/Adjustment.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AdjustmentVariants = Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::MonetaryUsageDiscountAdjustment Create( - Models::MonetaryUsageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryAmountDiscountAdjustment Create( - Models::MonetaryAmountDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryPercentageDiscountAdjustment Create( - Models::MonetaryPercentageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryMinimumAdjustment Create( - Models::MonetaryMinimumAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryMaximumAdjustment Create( - Models::MonetaryMaximumAdjustment value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/AdjustmentVariants/All.cs b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 97e6304c..00000000 --- a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,120 +0,0 @@ -using InvoiceLineItemCreateResponseProperties = Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryUsageDiscountAdjustment, - Models::MonetaryUsageDiscountAdjustment - >) -)] -public sealed record class MonetaryUsageDiscountAdjustment( - Models::MonetaryUsageDiscountAdjustment Value -) - : InvoiceLineItemCreateResponseProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryUsageDiscountAdjustment From( - Models::MonetaryUsageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryAmountDiscountAdjustment, - Models::MonetaryAmountDiscountAdjustment - >) -)] -public sealed record class MonetaryAmountDiscountAdjustment( - Models::MonetaryAmountDiscountAdjustment Value -) - : InvoiceLineItemCreateResponseProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryAmountDiscountAdjustment From( - Models::MonetaryAmountDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryPercentageDiscountAdjustment, - Models::MonetaryPercentageDiscountAdjustment - >) -)] -public sealed record class MonetaryPercentageDiscountAdjustment( - Models::MonetaryPercentageDiscountAdjustment Value -) - : InvoiceLineItemCreateResponseProperties::Adjustment, - Orb::IVariant< - MonetaryPercentageDiscountAdjustment, - Models::MonetaryPercentageDiscountAdjustment - > -{ - public static MonetaryPercentageDiscountAdjustment From( - Models::MonetaryPercentageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MonetaryMinimumAdjustment(Models::MonetaryMinimumAdjustment Value) - : InvoiceLineItemCreateResponseProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryMinimumAdjustment From(Models::MonetaryMinimumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MonetaryMaximumAdjustment(Models::MonetaryMaximumAdjustment Value) - : InvoiceLineItemCreateResponseProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryMaximumAdjustment From(Models::MonetaryMaximumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/SubLineItem.cs b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/SubLineItem.cs deleted file mode 100644 index 5f4d78a8..00000000 --- a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/SubLineItem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubLineItemVariants = Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties.SubLineItemVariants; - -namespace Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class SubLineItem -{ - internal SubLineItem() { } - - public static SubLineItemVariants::MatrixSubLineItem Create(Models::MatrixSubLineItem value) => - new(value); - - public static SubLineItemVariants::TierSubLineItem Create(Models::TierSubLineItem value) => - new(value); - - public static SubLineItemVariants::OtherSubLineItem Create(Models::OtherSubLineItem value) => - new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/SubLineItemVariants/All.cs b/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/SubLineItemVariants/All.cs deleted file mode 100644 index ef7d4d95..00000000 --- a/src/Orb/Models/InvoiceLineItems/InvoiceLineItemCreateResponseProperties/SubLineItemVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using InvoiceLineItemCreateResponseProperties = Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceLineItems.InvoiceLineItemCreateResponseProperties.SubLineItemVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MatrixSubLineItem(Models::MatrixSubLineItem Value) - : InvoiceLineItemCreateResponseProperties::SubLineItem, - Orb::IVariant -{ - public static MatrixSubLineItem From(Models::MatrixSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TierSubLineItem(Models::TierSubLineItem Value) - : InvoiceLineItemCreateResponseProperties::SubLineItem, - Orb::IVariant -{ - public static TierSubLineItem From(Models::TierSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class OtherSubLineItem(Models::OtherSubLineItem Value) - : InvoiceLineItemCreateResponseProperties::SubLineItem, - Orb::IVariant -{ - public static OtherSubLineItem From(Models::OtherSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/InvoiceProperties/AutoCollection.cs b/src/Orb/Models/InvoiceProperties/AutoCollection.cs deleted file mode 100644 index 60f75cca..00000000 --- a/src/Orb/Models/InvoiceProperties/AutoCollection.cs +++ /dev/null @@ -1,126 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AutoCollection : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// True only if auto-collection is enabled for this invoice. - /// - public required bool? Enabled - { - get - { - if (!this.Properties.TryGetValue("enabled", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "enabled", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["enabled"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If the invoice is scheduled for auto-collection, this field will reflect when - /// the next attempt will occur. If dunning has been exhausted, or auto-collection - /// is not enabled for this invoice, this field will be `null`. - /// - public required System::DateTime? NextAttemptAt - { - get - { - if (!this.Properties.TryGetValue("next_attempt_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "next_attempt_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["next_attempt_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Number of auto-collection payment attempts. - /// - public required long? NumAttempts - { - get - { - if (!this.Properties.TryGetValue("num_attempts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "num_attempts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["num_attempts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If Orb has ever attempted payment auto-collection for this invoice, this field - /// will reflect when that attempt occurred. In conjunction with `next_attempt_at`, - /// this can be used to tell whether the invoice is currently in dunning (that is, - /// `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), - /// or if dunning has been exhausted (`previously_attempted_at` is non-null, but - /// `next_attempt_time` is null). - /// - public required System::DateTime? PreviouslyAttemptedAt - { - get - { - if ( - !this.Properties.TryGetValue( - "previously_attempted_at", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "previously_attempted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["previously_attempted_at"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.Enabled; - _ = this.NextAttemptAt; - _ = this.NumAttempts; - _ = this.PreviouslyAttemptedAt; - } - - public AutoCollection() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AutoCollection(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AutoCollection FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/InvoiceProperties/CreditNote.cs b/src/Orb/Models/InvoiceProperties/CreditNote.cs deleted file mode 100644 index 82cb704e..00000000 --- a/src/Orb/Models/InvoiceProperties/CreditNote.cs +++ /dev/null @@ -1,148 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditNote : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string CreditNoteNumber - { - get - { - if (!this.Properties.TryGetValue("credit_note_number", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_note_number"); - } - set - { - this.Properties["credit_note_number"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An optional memo supplied on the credit note. - /// - public required string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("memo", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Reason - { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("reason"); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Total - { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Type - { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If the credit note has a status of `void`, this gives a timestamp when the - /// credit note was voided. - /// - public required System::DateTime? VoidedAt - { - get - { - if (!this.Properties.TryGetValue("voided_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["voided_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.CreditNoteNumber; - _ = this.Memo; - _ = this.Reason; - _ = this.Total; - _ = this.Type; - _ = this.VoidedAt; - } - - public CreditNote() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditNote(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static CreditNote FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/InvoiceProperties/CustomerBalanceTransaction.cs b/src/Orb/Models/InvoiceProperties/CustomerBalanceTransaction.cs deleted file mode 100644 index d4beab10..00000000 --- a/src/Orb/Models/InvoiceProperties/CustomerBalanceTransaction.cs +++ /dev/null @@ -1,221 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CustomerBalanceTransactionProperties = Orb.Models.InvoiceProperties.CustomerBalanceTransactionProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomerBalanceTransaction - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// A unique id for this transaction. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required CustomerBalanceTransactionProperties::Action Action - { - get - { - if (!this.Properties.TryGetValue("action", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "action", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("action"); - } - set { this.Properties["action"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The value of the amount changed in the transaction. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The creation time of this transaction. - /// - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::CreditNoteTiny? CreditNote - { - get - { - if (!this.Properties.TryGetValue("credit_note", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["credit_note"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional description provided for manual customer balance adjustments. - /// - public required string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The new value of the customer's balance prior to the transaction, in the customer's currency. - /// - public required string EndingBalance - { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("ending_balance"); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::InvoiceTiny? Invoice - { - get - { - if (!this.Properties.TryGetValue("invoice", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The original value of the customer's balance prior to the transaction, in the - /// customer's currency. - /// - public required string StartingBalance - { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("starting_balance"); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required CustomerBalanceTransactionProperties::Type Type - { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - this.Action.Validate(); - _ = this.Amount; - _ = this.CreatedAt; - this.CreditNote?.Validate(); - _ = this.Description; - _ = this.EndingBalance; - this.Invoice?.Validate(); - _ = this.StartingBalance; - this.Type.Validate(); - } - - public CustomerBalanceTransaction() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomerBalanceTransaction(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static CustomerBalanceTransaction FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/InvoiceProperties/CustomerBalanceTransactionProperties/Action.cs b/src/Orb/Models/InvoiceProperties/CustomerBalanceTransactionProperties/Action.cs deleted file mode 100644 index 2818d206..00000000 --- a/src/Orb/Models/InvoiceProperties/CustomerBalanceTransactionProperties/Action.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties.CustomerBalanceTransactionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Action(string value) : Orb::IEnum -{ - public static readonly Action AppliedToInvoice = new("applied_to_invoice"); - - public static readonly Action ManualAdjustment = new("manual_adjustment"); - - public static readonly Action ProratedRefund = new("prorated_refund"); - - public static readonly Action RevertProratedRefund = new("revert_prorated_refund"); - - public static readonly Action ReturnFromVoiding = new("return_from_voiding"); - - public static readonly Action CreditNoteApplied = new("credit_note_applied"); - - public static readonly Action CreditNoteVoided = new("credit_note_voided"); - - public static readonly Action OverpaymentRefund = new("overpayment_refund"); - - public static readonly Action ExternalPayment = new("external_payment"); - - readonly string _value = value; - - public enum Value - { - AppliedToInvoice, - ManualAdjustment, - ProratedRefund, - RevertProratedRefund, - ReturnFromVoiding, - CreditNoteApplied, - CreditNoteVoided, - OverpaymentRefund, - ExternalPayment, - } - - public Value Known() => - _value switch - { - "applied_to_invoice" => Value.AppliedToInvoice, - "manual_adjustment" => Value.ManualAdjustment, - "prorated_refund" => Value.ProratedRefund, - "revert_prorated_refund" => Value.RevertProratedRefund, - "return_from_voiding" => Value.ReturnFromVoiding, - "credit_note_applied" => Value.CreditNoteApplied, - "credit_note_voided" => Value.CreditNoteVoided, - "overpayment_refund" => Value.OverpaymentRefund, - "external_payment" => Value.ExternalPayment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Action FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/InvoiceProperties/CustomerBalanceTransactionProperties/Type.cs b/src/Orb/Models/InvoiceProperties/CustomerBalanceTransactionProperties/Type.cs deleted file mode 100644 index ec4f1bb8..00000000 --- a/src/Orb/Models/InvoiceProperties/CustomerBalanceTransactionProperties/Type.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties.CustomerBalanceTransactionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Increment = new("increment"); - - public static readonly Type Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/InvoiceProperties/InvoiceSource.cs b/src/Orb/Models/InvoiceProperties/InvoiceSource.cs deleted file mode 100644 index a36b18e5..00000000 --- a/src/Orb/Models/InvoiceProperties/InvoiceSource.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class InvoiceSource(string value) : Orb::IEnum -{ - public static readonly InvoiceSource Subscription = new("subscription"); - - public static readonly InvoiceSource Partial = new("partial"); - - public static readonly InvoiceSource OneOff = new("one_off"); - - readonly string _value = value; - - public enum Value - { - Subscription, - Partial, - OneOff, - } - - public Value Known() => - _value switch - { - "subscription" => Value.Subscription, - "partial" => Value.Partial, - "one_off" => Value.OneOff, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static InvoiceSource FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/InvoiceProperties/LineItem.cs b/src/Orb/Models/InvoiceProperties/LineItem.cs deleted file mode 100644 index 1cd28674..00000000 --- a/src/Orb/Models/InvoiceProperties/LineItem.cs +++ /dev/null @@ -1,500 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using LineItemProperties = Orb.Models.InvoiceProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LineItem : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A unique ID for this line item. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The line amount after any adjustments and before overage conversion, credits - /// and partial invoicing. - /// - public required string AdjustedSubtotal - { - get - { - if (!this.Properties.TryGetValue("adjusted_subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjusted_subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjusted_subtotal"); - } - set - { - this.Properties["adjusted_subtotal"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// All adjustments applied to the line item in the order they were applied based - /// on invoice calculations (ie. usage discounts -> amount discounts -> percentage - /// discounts -> minimums -> maximums). - /// - public required Generic::List Adjustments - { - get - { - if (!this.Properties.TryGetValue("adjustments", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustments", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustments"); - } - set { this.Properties["adjustments"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The final amount for a line item after all adjustments and pre paid credits - /// have been applied. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The number of prepaid credits applied. - /// - public required string CreditsApplied - { - get - { - if (!this.Properties.TryGetValue("credits_applied", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credits_applied", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credits_applied"); - } - set { this.Properties["credits_applied"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments` - /// - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the range of time applied for this line item's price. - /// - public required System::DateTime EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An additional filter that was used to calculate the usage for this line item. - /// - public required string? Filter - { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filter", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// [DEPRECATED] For configured prices that are split by a grouping key, this will - /// be populated with the key and a value. The `amount` and `subtotal` will be - /// the values for this particular grouping. - /// - public required string? Grouping - { - get - { - if (!this.Properties.TryGetValue("grouping", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["grouping"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price associated with this line item. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Any amount applied from a partial invoice - /// - public required string PartiallyInvoicedAmount - { - get - { - if ( - !this.Properties.TryGetValue( - "partially_invoiced_amount", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "partially_invoiced_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("partially_invoiced_amount"); - } - set - { - this.Properties["partially_invoiced_amount"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The Price resource represents a price that can be billed on a subscription, - /// resulting in a charge on an invoice in the form of an invoice line item. Prices - /// take a quantity and determine an amount to bill. - /// - /// Orb supports a few different pricing models out of the box. Each of these models - /// is serialized differently in a given Price object. The model_type field determines - /// the key for the configuration object that is present. - /// - /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) - /// - public required Models::Price Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("price", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price"); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Either the fixed fee quantity or the usage during the service period. - /// - public required double Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The start date of the range of time applied for this line item's price. - /// - public required System::DateTime StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For complex pricing structures, the line item can be broken down further in `sub_line_items`. - /// - public required Generic::List SubLineItems - { - get - { - if (!this.Properties.TryGetValue("sub_line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "sub_line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("sub_line_items"); - } - set { this.Properties["sub_line_items"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The line amount before before any adjustments. - /// - public required string Subtotal - { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An array of tax rates and their incurred tax amounts. Empty if no tax integration - /// is configured. - /// - public required Generic::List TaxAmounts - { - get - { - if (!this.Properties.TryGetValue("tax_amounts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_amounts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tax_amounts"); - } - set { this.Properties["tax_amounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A list of customer ids that were used to calculate the usage for this line item. - /// - public required Generic::List? UsageCustomerIDs - { - get - { - if (!this.Properties.TryGetValue("usage_customer_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_customer_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - _ = this.AdjustedSubtotal; - foreach (var item in this.Adjustments) - { - item.Validate(); - } - _ = this.Amount; - _ = this.CreditsApplied; - this.Discount?.Validate(); - _ = this.EndDate; - _ = this.Filter; - _ = this.Grouping; - this.Maximum?.Validate(); - _ = this.MaximumAmount; - this.Minimum?.Validate(); - _ = this.MinimumAmount; - _ = this.Name; - _ = this.PartiallyInvoicedAmount; - this.Price.Validate(); - _ = this.Quantity; - _ = this.StartDate; - foreach (var item in this.SubLineItems) - { - item.Validate(); - } - _ = this.Subtotal; - foreach (var item in this.TaxAmounts) - { - item.Validate(); - } - foreach (var item in this.UsageCustomerIDs ?? []) - { - _ = item; - } - } - - public LineItem() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LineItem(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static LineItem FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/InvoiceProperties/LineItemProperties/Adjustment.cs b/src/Orb/Models/InvoiceProperties/LineItemProperties/Adjustment.cs deleted file mode 100644 index 0f8eec3e..00000000 --- a/src/Orb/Models/InvoiceProperties/LineItemProperties/Adjustment.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AdjustmentVariants = Orb.Models.InvoiceProperties.LineItemProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceProperties.LineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::MonetaryUsageDiscountAdjustment Create( - Models::MonetaryUsageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryAmountDiscountAdjustment Create( - Models::MonetaryAmountDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryPercentageDiscountAdjustment Create( - Models::MonetaryPercentageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryMinimumAdjustment Create( - Models::MonetaryMinimumAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryMaximumAdjustment Create( - Models::MonetaryMaximumAdjustment value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/InvoiceProperties/LineItemProperties/AdjustmentVariants/All.cs b/src/Orb/Models/InvoiceProperties/LineItemProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 68da18e2..00000000 --- a/src/Orb/Models/InvoiceProperties/LineItemProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,120 +0,0 @@ -using LineItemProperties = Orb.Models.InvoiceProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceProperties.LineItemProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryUsageDiscountAdjustment, - Models::MonetaryUsageDiscountAdjustment - >) -)] -public sealed record class MonetaryUsageDiscountAdjustment( - Models::MonetaryUsageDiscountAdjustment Value -) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryUsageDiscountAdjustment From( - Models::MonetaryUsageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryAmountDiscountAdjustment, - Models::MonetaryAmountDiscountAdjustment - >) -)] -public sealed record class MonetaryAmountDiscountAdjustment( - Models::MonetaryAmountDiscountAdjustment Value -) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryAmountDiscountAdjustment From( - Models::MonetaryAmountDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryPercentageDiscountAdjustment, - Models::MonetaryPercentageDiscountAdjustment - >) -)] -public sealed record class MonetaryPercentageDiscountAdjustment( - Models::MonetaryPercentageDiscountAdjustment Value -) - : LineItemProperties::Adjustment, - Orb::IVariant< - MonetaryPercentageDiscountAdjustment, - Models::MonetaryPercentageDiscountAdjustment - > -{ - public static MonetaryPercentageDiscountAdjustment From( - Models::MonetaryPercentageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MonetaryMinimumAdjustment(Models::MonetaryMinimumAdjustment Value) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryMinimumAdjustment From(Models::MonetaryMinimumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MonetaryMaximumAdjustment(Models::MonetaryMaximumAdjustment Value) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryMaximumAdjustment From(Models::MonetaryMaximumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/InvoiceProperties/LineItemProperties/SubLineItem.cs b/src/Orb/Models/InvoiceProperties/LineItemProperties/SubLineItem.cs deleted file mode 100644 index dcdb74f6..00000000 --- a/src/Orb/Models/InvoiceProperties/LineItemProperties/SubLineItem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubLineItemVariants = Orb.Models.InvoiceProperties.LineItemProperties.SubLineItemVariants; - -namespace Orb.Models.InvoiceProperties.LineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class SubLineItem -{ - internal SubLineItem() { } - - public static SubLineItemVariants::MatrixSubLineItem Create(Models::MatrixSubLineItem value) => - new(value); - - public static SubLineItemVariants::TierSubLineItem Create(Models::TierSubLineItem value) => - new(value); - - public static SubLineItemVariants::OtherSubLineItem Create(Models::OtherSubLineItem value) => - new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/InvoiceProperties/LineItemProperties/SubLineItemVariants/All.cs b/src/Orb/Models/InvoiceProperties/LineItemProperties/SubLineItemVariants/All.cs deleted file mode 100644 index 23581405..00000000 --- a/src/Orb/Models/InvoiceProperties/LineItemProperties/SubLineItemVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using LineItemProperties = Orb.Models.InvoiceProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.InvoiceProperties.LineItemProperties.SubLineItemVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MatrixSubLineItem(Models::MatrixSubLineItem Value) - : LineItemProperties::SubLineItem, - Orb::IVariant -{ - public static MatrixSubLineItem From(Models::MatrixSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TierSubLineItem(Models::TierSubLineItem Value) - : LineItemProperties::SubLineItem, - Orb::IVariant -{ - public static TierSubLineItem From(Models::TierSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class OtherSubLineItem(Models::OtherSubLineItem Value) - : LineItemProperties::SubLineItem, - Orb::IVariant -{ - public static OtherSubLineItem From(Models::OtherSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/InvoiceProperties/PaymentAttempt.cs b/src/Orb/Models/InvoiceProperties/PaymentAttempt.cs deleted file mode 100644 index 38c9051d..00000000 --- a/src/Orb/Models/InvoiceProperties/PaymentAttempt.cs +++ /dev/null @@ -1,155 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PaymentAttemptProperties = Orb.Models.InvoiceProperties.PaymentAttemptProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PaymentAttempt : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The ID of the payment attempt. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The amount of the payment attempt. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The time at which the payment attempt was created. - /// - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The payment provider that attempted to collect the payment. - /// - public required PaymentAttemptProperties::PaymentProvider? PaymentProvider - { - get - { - if (!this.Properties.TryGetValue("payment_provider", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_provider", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["payment_provider"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The ID of the payment attempt in the payment provider. - /// - public required string? PaymentProviderID - { - get - { - if (!this.Properties.TryGetValue("payment_provider_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_provider_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_provider_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// Whether the payment attempt succeeded. - /// - public required bool Succeeded - { - get - { - if (!this.Properties.TryGetValue("succeeded", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "succeeded", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["succeeded"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Amount; - _ = this.CreatedAt; - this.PaymentProvider?.Validate(); - _ = this.PaymentProviderID; - _ = this.Succeeded; - } - - public PaymentAttempt() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PaymentAttempt(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PaymentAttempt FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/InvoiceProperties/PaymentAttemptProperties/PaymentProvider.cs b/src/Orb/Models/InvoiceProperties/PaymentAttemptProperties/PaymentProvider.cs deleted file mode 100644 index 3b4d5966..00000000 --- a/src/Orb/Models/InvoiceProperties/PaymentAttemptProperties/PaymentProvider.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties.PaymentAttemptProperties; - -/// -/// The payment provider that attempted to collect the payment. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PaymentProvider(string value) : Orb::IEnum -{ - public static readonly PaymentProvider Stripe = new("stripe"); - - readonly string _value = value; - - public enum Value - { - Stripe, - } - - public Value Known() => - _value switch - { - "stripe" => Value.Stripe, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PaymentProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/InvoiceProperties/Status.cs b/src/Orb/Models/InvoiceProperties/Status.cs deleted file mode 100644 index 4f3f7524..00000000 --- a/src/Orb/Models/InvoiceProperties/Status.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.InvoiceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Issued = new("issued"); - - public static readonly Status Paid = new("paid"); - - public static readonly Status Synced = new("synced"); - - public static readonly Status Void = new("void"); - - public static readonly Status Draft = new("draft"); - - readonly string _value = value; - - public enum Value - { - Issued, - Paid, - Synced, - Void, - Draft, - } - - public Value Known() => - _value switch - { - "issued" => Value.Issued, - "paid" => Value.Paid, - "synced" => Value.Synced, - "void" => Value.Void, - "draft" => Value.Draft, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/InvoiceTiny.cs b/src/Orb/Models/InvoiceTiny.cs index bbbdbc83..d4f4faae 100644 --- a/src/Orb/Models/InvoiceTiny.cs +++ b/src/Orb/Models/InvoiceTiny.cs @@ -1,31 +1,25 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceTiny : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceTiny : JsonModel { /// /// The Invoice id /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } + /// public override void Validate() { _ = this.ID; @@ -33,18 +27,39 @@ public override void Validate() public InvoiceTiny() { } + public InvoiceTiny(InvoiceTiny invoiceTiny) + : base(invoiceTiny) { } + + public InvoiceTiny(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceTiny(Generic::Dictionary properties) + [SetsRequiredMembers] + InvoiceTiny(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static InvoiceTiny FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static InvoiceTiny FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public InvoiceTiny(string id) + : this() { - return new(properties); + this.ID = id; } } + +class InvoiceTinyFromRaw : IFromRawJson +{ + /// + public InvoiceTiny FromRawUnchecked(IReadOnlyDictionary rawData) => + InvoiceTiny.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Invoices/InvoiceCreateParams.cs b/src/Orb/Models/Invoices/InvoiceCreateParams.cs index 3b995908..25479753 100644 --- a/src/Orb/Models/Invoices/InvoiceCreateParams.cs +++ b/src/Orb/Models/Invoices/InvoiceCreateParams.cs @@ -1,20 +1,26 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using InvoiceCreateParamsProperties = Orb.Models.Invoices.InvoiceCreateParamsProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Invoices; /// /// This endpoint is used to create a one-off invoice for a customer. /// -public sealed record class InvoiceCreateParams : Orb::ParamsBase +public sealed record class InvoiceCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// An ISO 4217 currency string. Must be the same as the customer's currency if @@ -22,211 +28,585 @@ public sealed record class InvoiceCreateParams : Orb::ParamsBase /// public required string Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } /// /// Optional invoice date to set. Must be in the past, if not set, `invoice_date` /// is set to the current time in the customer's timezone. /// - public required System::DateTime InvoiceDate + public required System::DateTimeOffset InvoiceDate { get { - if (!this.BodyProperties.TryGetValue("invoice_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["invoice_date"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct( + this.RawBodyData, + "invoice_date" + ); } + init { JsonModel.Set(this._rawBodyData, "invoice_date", value); } } - public required Generic::List LineItems + public required IReadOnlyList LineItems { get { - if (!this.BodyProperties.TryGetValue("line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("line_items"); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "line_items" + ); } - set { this.BodyProperties["line_items"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "line_items", value); } } /// - /// Determines the difference between the invoice issue date for subscription invoices - /// as the date that they are due. A value of '0' here represents that the invoice - /// is due on issue, whereas a value of 30 represents that the customer has 30 days - /// to pay the invoice. + /// The id of the `Customer` to create this invoice for. One of `customer_id` + /// and `external_customer_id` are required. /// - public required long NetTerms + public string? CustomerID { - get - { - if (!this.BodyProperties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// An optional discount to attach to the invoice. + /// + public SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "discount"); } + init { JsonModel.Set(this._rawBodyData, "discount", value); } } /// - /// The id of the `Customer` to create this invoice for. One of `customer_id` and - /// `external_customer_id` are required. + /// An optional custom due date for the invoice. If not set, the due date will + /// be calculated based on the `net_terms` value. /// - public string? CustomerID + public DueDate? DueDate { - get - { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "due_date"); } + init { JsonModel.Set(this._rawBodyData, "due_date", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// The `external_customer_id` of the `Customer` to create this invoice for. + /// One of `customer_id` and `external_customer_id` are required. + /// + public string? ExternalCustomerID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } /// - /// An optional discount to attach to the invoice. + /// An optional memo to attach to the invoice. If no memo is provided, we will + /// attach the default memo + /// + public string? Memo + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "memo"); } + init { JsonModel.Set(this._rawBodyData, "memo", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. /// - public Models::Discount? Discount + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("discount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } /// - /// The `external_customer_id` of the `Customer` to create this invoice for. One - /// of `customer_id` and `external_customer_id` are required. + /// The net terms determines the due date of the invoice. Due date is calculated + /// based on the invoice or issuance date, depending on the account's configured + /// due date calculation method. A value of '0' here represents that the invoice + /// is due on issue, whereas a value of '30' represents that the customer has + /// 30 days to pay the invoice. Do not set this field if you want to set a custom + /// due date. /// - public string? ExternalCustomerID + public long? NetTerms { - get + get { return JsonModel.GetNullableStruct(this.RawBodyData, "net_terms"); } + init { JsonModel.Set(this._rawBodyData, "net_terms", value); } + } + + /// + /// When true, this invoice will be submitted for issuance upon creation. When + /// false, the resulting invoice will require manual review to issue. Defaulted + /// to false. + /// + public bool? WillAutoIssue + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "will_auto_issue"); } + init { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "will_auto_issue", value); } - set + } + + public InvoiceCreateParams() { } + + public InvoiceCreateParams(InvoiceCreateParams invoiceCreateParams) + : base(invoiceCreateParams) + { + this._rawBodyData = [.. invoiceCreateParams._rawBodyData]; + } + + public InvoiceCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/invoices") { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } +} +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Invoices.LineItem, + global::Orb.Models.Invoices.LineItemFromRaw + >) +)] +public sealed record class LineItem : JsonModel +{ /// - /// An optional memo to attach to the invoice. + /// A date string to specify the line item's end date in the customer's timezone. /// - public string? Memo + public required string EndDate + { + get { return JsonModel.GetNotNullClass(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + public required ApiEnum ModelType { get { - if (!this.BodyProperties.TryGetValue("memo", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.BodyProperties["memo"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. + /// The name of the line item. /// - public Generic::Dictionary? Metadata + public required string Name { - get + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The number of units on the line item + /// + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + /// A date string to specify the line item's start date in the customer's timezone. + /// + public required string StartDate + { + get { return JsonModel.GetNotNullClass(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + /// Configuration for unit pricing + /// + public required UnitConfig UnitConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_config"); } + init { JsonModel.Set(this._rawData, "unit_config", value); } + } + + /// + public override void Validate() + { + _ = this.EndDate; + _ = this.ItemID; + this.ModelType.Validate(); + _ = this.Name; + _ = this.Quantity; + _ = this.StartDate; + this.UnitConfig.Validate(); + } + + public LineItem() { } + + public LineItem(global::Orb.Models.Invoices.LineItem lineItem) + : base(lineItem) { } + + public LineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + LineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Invoices.LineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class LineItemFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Invoices.LineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Invoices.LineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.ModelTypeConverter))] +public enum ModelType +{ + Unit, +} + +sealed class ModelTypeConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.ModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; + "unit" => global::Orb.Models.Invoices.ModelType.Unit, + _ => (global::Orb.Models.Invoices.ModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.ModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Invoices.ModelType.Unit => "unit", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// An optional custom due date for the invoice. If not set, the due date will be +/// calculated based on the `net_terms` value. +/// +[JsonConverter(typeof(DueDateConverter))] +public record class DueDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } - return Json::JsonSerializer.Deserialize?>(element); + public DueDate(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DueDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DueDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of DueDate"); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } } /// - /// When true, this invoice will be submitted for issuance upon creation. When false, - /// the resulting invoice will require manual review to issue. Defaulted to false. + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// /// - public bool? WillAutoIssue + public T Match( + System::Func @date, + System::Func @dateTime + ) { - get + return this.Value switch { - if (!this.BodyProperties.TryGetValue("will_auto_issue", out Json::JsonElement element)) - return null; + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of DueDate"), + }; + } - return Json::JsonSerializer.Deserialize(element); - } - set + public static implicit operator DueDate(string value) => new(value); + + public static implicit operator DueDate(System::DateTimeOffset value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) { - this.BodyProperties["will_auto_issue"] = Json::JsonSerializer.SerializeToElement(value); + throw new OrbInvalidDataException("Data did not match any variant of DueDate"); } } - public override System::Uri Url(Orb::IOrbClient client) + public virtual bool Equals(DueDate? other) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/invoices") - { - Query = this.QueryString(client), - }.Uri; + return other != null && JsonElement.DeepEquals(this.Json, other.Json); } - public Http::StringContent BodyContent() + public override int GetHashCode() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + return 0; } +} - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) +sealed class DueDateConverter : JsonConverter +{ + public override DueDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return new(JsonSerializer.Deserialize(element, options)); } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write(Utf8JsonWriter writer, DueDate? value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value?.Json, options); } } diff --git a/src/Orb/Models/Invoices/InvoiceCreateParamsProperties/LineItem.cs b/src/Orb/Models/Invoices/InvoiceCreateParamsProperties/LineItem.cs deleted file mode 100644 index 8e2d2712..00000000 --- a/src/Orb/Models/Invoices/InvoiceCreateParamsProperties/LineItem.cs +++ /dev/null @@ -1,160 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using LineItemProperties = Orb.Models.Invoices.InvoiceCreateParamsProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LineItem : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A date string to specify the line item's end date in the customer's timezone. - /// - public required System::DateOnly EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required LineItemProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the line item. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The number of units on the line item - /// - public required double Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A date string to specify the line item's start date in the customer's timezone. - /// - public required System::DateOnly StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::UnitConfig UnitConfig - { - get - { - if (!this.Properties.TryGetValue("unit_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_config"); - } - set { this.Properties["unit_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.EndDate; - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.Quantity; - _ = this.StartDate; - this.UnitConfig.Validate(); - } - - public LineItem() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LineItem(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static LineItem FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceCreateParamsProperties/LineItemProperties/ModelType.cs b/src/Orb/Models/Invoices/InvoiceCreateParamsProperties/LineItemProperties/ModelType.cs deleted file mode 100644 index f177acf7..00000000 --- a/src/Orb/Models/Invoices/InvoiceCreateParamsProperties/LineItemProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceCreateParamsProperties.LineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Unit = new("unit"); - - readonly string _value = value; - - public enum Value - { - Unit, - } - - public Value Known() => - _value switch - { - "unit" => Value.Unit, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchParams.cs b/src/Orb/Models/Invoices/InvoiceFetchParams.cs index 474f3158..b4068c89 100644 --- a/src/Orb/Models/Invoices/InvoiceFetchParams.cs +++ b/src/Orb/Models/Invoices/InvoiceFetchParams.cs @@ -1,32 +1,74 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Invoices; /// /// This endpoint is used to fetch an [`Invoice`](/core-concepts#invoice) given an identifier. /// -public sealed record class InvoiceFetchParams : Orb::ParamsBase +public sealed record class InvoiceFetchParams : ParamsBase { - public required string InvoiceID; + public string? InvoiceID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public InvoiceFetchParams() { } + + public InvoiceFetchParams(InvoiceFetchParams invoiceFetchParams) + : base(invoiceFetchParams) { } + + public InvoiceFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}", this.InvoiceID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}", this.InvoiceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingParams.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingParams.cs index 5d9a7ccf..404819cc 100644 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingParams.cs +++ b/src/Orb/Models/Invoices/InvoiceFetchUpcomingParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Invoices; @@ -9,43 +12,66 @@ namespace Orb.Models.Invoices; /// This endpoint can be used to fetch the upcoming [invoice](/core-concepts#invoice) /// for the current billing period given a subscription. ///
-public sealed record class InvoiceFetchUpcomingParams : Orb::ParamsBase +public sealed record class InvoiceFetchUpcomingParams : ParamsBase { public required string SubscriptionID { - get - { - if (!this.QueryProperties.TryGetValue("subscription_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subscription_id"); - } - set - { - this.QueryProperties["subscription_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawQueryData, "subscription_id"); } + init { JsonModel.Set(this._rawQueryData, "subscription_id", value); } + } + + public InvoiceFetchUpcomingParams() { } + + public InvoiceFetchUpcomingParams(InvoiceFetchUpcomingParams invoiceFetchUpcomingParams) + : base(invoiceFetchUpcomingParams) { } + + public InvoiceFetchUpcomingParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceFetchUpcomingParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceFetchUpcomingParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/invoices/upcoming") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/invoices/upcoming") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponse.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponse.cs index af6e54a5..a45fc4c3 100644 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponse.cs +++ b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponse.cs @@ -1,30 +1,23 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using InvoiceFetchUpcomingResponseProperties = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Invoices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceFetchUpcomingResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class InvoiceFetchUpcomingResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -33,332 +26,224 @@ public required string ID /// public required string AmountDue { - get - { - if (!this.Properties.TryGetValue("amount_due", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_due", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_due"); - } - set { this.Properties["amount_due"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_due"); } + init { JsonModel.Set(this._rawData, "amount_due", value); } } - public required InvoiceFetchUpcomingResponseProperties::AutoCollection AutoCollection + public required global::Orb.Models.Invoices.AutoCollection AutoCollection { get { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("auto_collection"); + return JsonModel.GetNotNullClass( + this.RawData, + "auto_collection" + ); } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } } - public required Models::Address? BillingAddress + public required Address? BillingAddress { - get - { - if (!this.Properties.TryGetValue("billing_address", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billing_address", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billing_address"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass
(this.RawData, "billing_address"); } + init { JsonModel.Set(this._rawData, "billing_address", value); } } /// /// The creation time of the resource in Orb. /// - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// /// A list of credit notes associated with the invoice /// - public required Generic::List CreditNotes + public required IReadOnlyList CreditNotes { get { - if (!this.Properties.TryGetValue("credit_notes", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_notes", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("credit_notes"); + return JsonModel.GetNotNullClass>( + this.RawData, + "credit_notes" + ); } - set { this.Properties["credit_notes"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "credit_notes", value); } } /// /// An ISO 4217 currency string or `credits` /// public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + public required CustomerMinified Customer + { + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } + } + + public required IReadOnlyList CustomerBalanceTransactions { get { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::CustomerMinified Customer - { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::List CustomerBalanceTransactions - { - get - { - if ( - !this.Properties.TryGetValue( - "customer_balance_transactions", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "customer_balance_transactions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("customer_balance_transactions"); - } - set - { - this.Properties["customer_balance_transactions"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// Tax IDs are commonly required to be displayed on customer invoices, which are - /// added to the headers of invoices. - /// - /// ### Supported Tax ID Countries and Types - /// - /// | Country | Type | Description - /// | |----------------|--------------|---------------------------------------------| - /// | Andorra | `ad_nrt` | Andorran NRT Number - /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number - /// | | Australia | `au_abn` | Australian Business Number (AU ABN) - /// | | Australia | `au_arn` | Australian Taxation Office - /// Reference Number | | Austria | `eu_vat` | European VAT Number - /// | | Bahrain | `bh_vat` | Bahraini VAT Number - /// | | Belgium | `eu_vat` | European VAT Number - /// | | Bolivia | `bo_tin` | Bolivian Tax ID - /// | | Brazil | `br_cnpj` | Brazilian CNPJ - /// Number | | Brazil | `br_cpf` | Brazilian CPF - /// Number | | Bulgaria | `bg_uic` | Bulgaria - /// Unified Identification Code | | Bulgaria | `eu_vat` | European - /// VAT Number | | Canada | `ca_bn` | Canadian - /// BN | | Canada | `ca_gst_hst` | Canadian - /// GST/HST Number | | Canada | `ca_pst_bc` | Canadian - /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian - /// PST Number (Manitoba) | | Canada | `ca_pst_sk` | Canadian - /// PST Number (Saskatchewan) | | Canada | `ca_qst` | Canadian - /// QST Number (Québec) | | Chile | `cl_tin` | Chilean - /// TIN | | China | `cn_tin` | Chinese - /// Tax ID | | Colombia | `co_nit` | Colombian - /// NIT Number | | Costa Rica | `cr_tin` | Costa - /// Rican Tax ID | | Croatia | `eu_vat` | European - /// VAT Number | | Cyprus | `eu_vat` | European - /// VAT Number | | Czech Republic | `eu_vat` | European - /// VAT Number | | Denmark | `eu_vat` | European - /// VAT Number | | Dominican Republic | `do_rcn` | Dominican - /// RCN Number | | Ecuador | `ec_ruc` | Ecuadorian - /// RUC Number | | Egypt | `eg_tin` | Egyptian - /// Tax Identification Number | | El Salvador | `sv_nit` - /// | El Salvadorian NIT Number | | Estonia | `eu_vat` | - /// European VAT Number | | EU | `eu_oss_vat` | European One Stop Shop - /// VAT Number for non-Union scheme | | Finland | `eu_vat` | European VAT - /// Number | | France | `eu_vat` | European - /// VAT Number | | Georgia | `ge_vat` | - /// Georgian VAT | | Germany | `eu_vat` - /// | European VAT Number | | Greece - /// | `eu_vat` | European VAT Number | | - /// Hong Kong | `hk_br` | Hong Kong BR Number - /// | | Hungary | `eu_vat` | European VAT Number - /// | | Hungary | `hu_tin` | Hungary Tax Number (adószám) - /// | | Iceland | `is_vat` | Icelandic VAT - /// | | India | `in_gst` | Indian GST - /// Number | | Indonesia | `id_npwp` | Indonesian - /// NPWP Number | | Ireland | `eu_vat` | - /// European VAT Number | | Israel | `il_vat` - /// | Israel VAT | | Italy - /// | `eu_vat` | European VAT Number | | - /// Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) - /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' - /// Registration Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | - /// Japan | `jp_trn` | Japanese Tax Registration Number (*Tōroku Bangō*) - /// | | Kazakhstan | `kz_bin` | Kazakhstani Business Identification - /// Number | | Kenya | `ke_pin` | Kenya Revenue Authority - /// Personal Identification Number | | Latvia | `eu_vat` | European VAT Number - /// | | Liechtenstein | `li_uid` | Liechtensteinian - /// UID Number | | Lithuania | `eu_vat` | European VAT Number - /// | | Luxembourg | `eu_vat` | European VAT Number - /// | | Malaysia | `my_frp` | Malaysian FRP Number - /// | | Malaysia | `my_itn` | Malaysian ITN - /// | | Malaysia | `my_sst` | Malaysian SST Number | - /// | Malta | `eu_vat ` | European VAT Number | | Mexico - /// | `mx_rfc` | Mexican RFC Number | | Netherlands - /// | `eu_vat` | European VAT Number | | New Zealand | - /// `nz_gst` | New Zealand GST Number | | Nigeria | - /// `ng_tin` | Nigerian Tax Identification Number | | Norway | `no_vat` - /// | Norwegian VAT Number | | Norway | `no_voec` | Norwegian - /// VAT on e-commerce Number | | Oman | `om_vat` | Omani VAT Number - /// | | Peru | `pe_ruc` | Peruvian RUC Number - /// | | Philippines | `ph_tin ` | Philippines Tax Identification - /// Number | | Poland | `eu_vat` | European VAT Number - /// | | Portugal | `eu_vat` | European VAT Number | | - /// Romania | `eu_vat` | European VAT Number | | Romania - /// | `ro_tin` | Romanian Tax ID Number | | Russia - /// | `ru_inn` | Russian INN | | Russia | `ru_kpp` - /// | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi - /// Arabia VAT | | Serbia | `rs_pib` | Serbian PIB - /// Number | | Singapore | `sg_gst` | Singaporean GST - /// | | Singapore | `sg_uen` | Singaporean UEN - /// | | Slovakia | `eu_vat` | European VAT Number - /// | | Slovenia | `eu_vat` | European VAT Number - /// | | Slovenia | `si_tin` | Slovenia Tax Number (davčna številka) - /// | | South Africa | `za_vat` | South African VAT - /// Number | | South Korea | `kr_brn` | Korean - /// BRN | | Spain | `es_cif` - /// | Spanish NIF Number (previously Spanish CIF Number) | | Spain - /// | `eu_vat` | European VAT Number | | - /// Sweden | `eu_vat` | European VAT Number - /// | | Switzerland | `ch_vat` | Switzerland VAT Number - /// | | Taiwan | `tw_vat` | Taiwanese VAT - /// | | Thailand | `th_vat` | - /// Thai VAT | | Turkey - /// | `tr_tin` | Turkish Tax Identification Number | | Ukraine - /// | `ua_vat` | Ukrainian VAT - /// | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN - /// | | United Kingdom | `eu_vat` | Northern Ireland - /// VAT Number | | United Kingdom | `gb_vat` | United - /// Kingdom VAT Number | | United States | `us_ein` - /// | United States EIN | | Uruguay - /// | `uy_ruc` | Uruguayan RUC Number | | Venezuela - /// | `ve_rif` | Venezuelan RIF Number - /// | | Vietnam | `vn_tin` | Vietnamese Tax ID Number - /// | - /// - public required Models::CustomerTaxID? CustomerTaxID - { - get - { - if (!this.Properties.TryGetValue("customer_tax_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer_tax_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_tax_id"] = Json::JsonSerializer.SerializeToElement(value); } + return JsonModel.GetNotNullClass< + List + >(this.RawData, "customer_balance_transactions"); + } + init { JsonModel.Set(this._rawData, "customer_balance_transactions", value); } } /// - /// This field is deprecated in favor of `discounts`. If a `discounts` list is - /// provided, the first discount in the list will be returned. If the list is empty, - /// `None` will be returned. + /// Tax IDs are commonly required to be displayed on customer invoices, which + /// are added to the headers of invoices. + /// + /// ### Supported Tax ID Countries and Types + /// + /// | Country | Type | Description | |---------|------|-------------| | + /// Albania | `al_tin` | Albania Tax Identification Number | | Andorra | `ad_nrt` + /// | Andorran NRT Number | | Angola | `ao_tin` | Angola Tax Identification Number + /// | | Argentina | `ar_cuit` | Argentinian Tax ID Number | | Armenia | `am_tin` + /// | Armenia Tax Identification Number | | Aruba | `aw_tin` | Aruba Tax Identification + /// Number | | Australia | `au_abn` | Australian Business Number (AU ABN) | | + /// Australia | `au_arn` | Australian Taxation Office Reference Number | | Austria + /// | `eu_vat` | European VAT Number | | Azerbaijan | `az_tin` | Azerbaijan Tax + /// Identification Number | | Bahamas | `bs_tin` | Bahamas Tax Identification + /// Number | | Bahrain | `bh_vat` | Bahraini VAT Number | | Bangladesh | `bd_bin` + /// | Bangladesh Business Identification Number | | Barbados | `bb_tin` | Barbados + /// Tax Identification Number | | Belarus | `by_tin` | Belarus TIN Number | | + /// Belgium | `eu_vat` | European VAT Number | | Benin | `bj_ifu` | Benin Tax + /// Identification Number (Identifiant Fiscal Unique) | | Bolivia | `bo_tin` + /// | Bolivian Tax ID | | Bosnia and Herzegovina | `ba_tin` | Bosnia and Herzegovina + /// Tax Identification Number | | Brazil | `br_cnpj` | Brazilian CNPJ Number | + /// | Brazil | `br_cpf` | Brazilian CPF Number | | Bulgaria | `bg_uic` | Bulgaria + /// Unified Identification Code | | Bulgaria | `eu_vat` | European VAT Number + /// | | Burkina Faso | `bf_ifu` | Burkina Faso Tax Identification Number (Numéro + /// d'Identifiant Fiscal Unique) | | Cambodia | `kh_tin` | Cambodia Tax Identification + /// Number | | Cameroon | `cm_niu` | Cameroon Tax Identification Number (Numéro + /// d'Identifiant fiscal Unique) | | Canada | `ca_bn` | Canadian BN | | Canada + /// | `ca_gst_hst` | Canadian GST/HST Number | | Canada | `ca_pst_bc` | Canadian + /// PST Number (British Columbia) | | Canada | `ca_pst_mb` | Canadian PST Number + /// (Manitoba) | | Canada | `ca_pst_sk` | Canadian PST Number (Saskatchewan) | + /// | Canada | `ca_qst` | Canadian QST Number (Québec) | | Cape Verde | `cv_nif` + /// | Cape Verde Tax Identification Number (Número de Identificação Fiscal) | + /// | Chile | `cl_tin` | Chilean TIN | | China | `cn_tin` | Chinese Tax ID | | + /// Colombia | `co_nit` | Colombian NIT Number | | Congo-Kinshasa | `cd_nif` + /// | Congo (DR) Tax Identification Number (Número de Identificação Fiscal) | + /// | Costa Rica | `cr_tin` | Costa Rican Tax ID | | Croatia | `eu_vat` | European + /// VAT Number | | Croatia | `hr_oib` | Croatian Personal Identification Number + /// (OIB) | | Cyprus | `eu_vat` | European VAT Number | | Czech Republic | `eu_vat` + /// | European VAT Number | | Denmark | `eu_vat` | European VAT Number | | Dominican + /// Republic | `do_rcn` | Dominican RCN Number | | Ecuador | `ec_ruc` | Ecuadorian + /// RUC Number | | Egypt | `eg_tin` | Egyptian Tax Identification Number | | + /// El Salvador | `sv_nit` | El Salvadorian NIT Number | | Estonia | `eu_vat` + /// | European VAT Number | | Ethiopia | `et_tin` | Ethiopia Tax Identification + /// Number | | European Union | `eu_oss_vat` | European One Stop Shop VAT Number + /// for non-Union scheme | | Finland | `eu_vat` | European VAT Number | | France + /// | `eu_vat` | European VAT Number | | Georgia | `ge_vat` | Georgian VAT | | + /// Germany | `de_stn` | German Tax Number (Steuernummer) | | Germany | `eu_vat` + /// | European VAT Number | | Greece | `eu_vat` | European VAT Number | | Guinea + /// | `gn_nif` | Guinea Tax Identification Number (Número de Identificação Fiscal) + /// | | Hong Kong | `hk_br` | Hong Kong BR Number | | Hungary | `eu_vat` | European + /// VAT Number | | Hungary | `hu_tin` | Hungary Tax Number (adószám) | | Iceland + /// | `is_vat` | Icelandic VAT | | India | `in_gst` | Indian GST Number | | Indonesia + /// | `id_npwp` | Indonesian NPWP Number | | Ireland | `eu_vat` | European VAT + /// Number | | Israel | `il_vat` | Israel VAT | | Italy | `eu_vat` | European + /// VAT Number | | Japan | `jp_cn` | Japanese Corporate Number (*Hōjin Bangō*) + /// | | Japan | `jp_rn` | Japanese Registered Foreign Businesses' Registration + /// Number (*Tōroku Kokugai Jigyōsha no Tōroku Bangō*) | | Japan | `jp_trn` | + /// Japanese Tax Registration Number (*Tōroku Bangō*) | | Kazakhstan | `kz_bin` + /// | Kazakhstani Business Identification Number | | Kenya | `ke_pin` | Kenya + /// Revenue Authority Personal Identification Number | | Kyrgyzstan | `kg_tin` + /// | Kyrgyzstan Tax Identification Number | | Laos | `la_tin` | Laos Tax Identification + /// Number | | Latvia | `eu_vat` | European VAT Number | | Liechtenstein | `li_uid` + /// | Liechtensteinian UID Number | | Liechtenstein | `li_vat` | Liechtenstein + /// VAT Number | | Lithuania | `eu_vat` | European VAT Number | | Luxembourg + /// | `eu_vat` | European VAT Number | | Malaysia | `my_frp` | Malaysian FRP + /// Number | | Malaysia | `my_itn` | Malaysian ITN | | Malaysia | `my_sst` | Malaysian + /// SST Number | | Malta | `eu_vat` | European VAT Number | | Mauritania | `mr_nif` + /// | Mauritania Tax Identification Number (Número de Identificação Fiscal) | + /// | Mexico | `mx_rfc` | Mexican RFC Number | | Moldova | `md_vat` | Moldova + /// VAT Number | | Montenegro | `me_pib` | Montenegro PIB Number | | Morocco | + /// `ma_vat` | Morocco VAT Number | | Nepal | `np_pan` | Nepal PAN Number | | + /// Netherlands | `eu_vat` | European VAT Number | | New Zealand | `nz_gst` | + /// New Zealand GST Number | | Nigeria | `ng_tin` | Nigerian Tax Identification + /// Number | | North Macedonia | `mk_vat` | North Macedonia VAT Number | | Northern + /// Ireland | `eu_vat` | Northern Ireland VAT Number | | Norway | `no_vat` | + /// Norwegian VAT Number | | Norway | `no_voec` | Norwegian VAT on e-commerce + /// Number | | Oman | `om_vat` | Omani VAT Number | | Peru | `pe_ruc` | Peruvian + /// RUC Number | | Philippines | `ph_tin` | Philippines Tax Identification Number + /// | | Poland | `eu_vat` | European VAT Number | | Portugal | `eu_vat` | European + /// VAT Number | | Romania | `eu_vat` | European VAT Number | | Romania | `ro_tin` + /// | Romanian Tax ID Number | | Russia | `ru_inn` | Russian INN | | Russia | + /// `ru_kpp` | Russian KPP | | Saudi Arabia | `sa_vat` | Saudi Arabia VAT | | + /// Senegal | `sn_ninea` | Senegal NINEA Number | | Serbia | `rs_pib` | Serbian + /// PIB Number | | Singapore | `sg_gst` | Singaporean GST | | Singapore | `sg_uen` + /// | Singaporean UEN | | Slovakia | `eu_vat` | European VAT Number | | Slovenia + /// | `eu_vat` | European VAT Number | | Slovenia | `si_tin` | Slovenia Tax Number + /// (davčna številka) | | South Africa | `za_vat` | South African VAT Number | + /// | South Korea | `kr_brn` | Korean BRN | | Spain | `es_cif` | Spanish NIF + /// Number (previously Spanish CIF Number) | | Spain | `eu_vat` | European VAT + /// Number | | Suriname | `sr_fin` | Suriname FIN Number | | Sweden | `eu_vat` + /// | European VAT Number | | Switzerland | `ch_uid` | Switzerland UID Number + /// | | Switzerland | `ch_vat` | Switzerland VAT Number | | Taiwan | `tw_vat` + /// | Taiwanese VAT | | Tajikistan | `tj_tin` | Tajikistan Tax Identification + /// Number | | Tanzania | `tz_vat` | Tanzania VAT Number | | Thailand | `th_vat` + /// | Thai VAT | | Turkey | `tr_tin` | Turkish Tax Identification Number | | Uganda + /// | `ug_tin` | Uganda Tax Identification Number | | Ukraine | `ua_vat` | Ukrainian + /// VAT | | United Arab Emirates | `ae_trn` | United Arab Emirates TRN | | United + /// Kingdom | `gb_vat` | United Kingdom VAT Number | | United States | `us_ein` + /// | United States EIN | | Uruguay | `uy_ruc` | Uruguayan RUC Number | | Uzbekistan + /// | `uz_tin` | Uzbekistan TIN Number | | Uzbekistan | `uz_vat` | Uzbekistan + /// VAT Number | | Venezuela | `ve_rif` | Venezuelan RIF Number | | Vietnam | + /// `vn_tin` | Vietnamese Tax ID Number | | Zambia | `zm_tin` | Zambia Tax Identification + /// Number | | Zimbabwe | `zw_tin` | Zimbabwe Tax Identification Number | /// - public required Json::JsonElement Discount + public required CustomerTaxID? CustomerTaxID { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); + get { return JsonModel.GetNullableClass(this.RawData, "customer_tax_id"); } + init { JsonModel.Set(this._rawData, "customer_tax_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// This field is deprecated in favor of `discounts`. If a `discounts` list is + /// provided, the first discount in the list will be returned. If the list is + /// empty, `None` will be returned. + /// + [System::Obsolete("deprecated")] + public required JsonElement Discount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } } - public required Generic::List Discounts + public required IReadOnlyList Discounts { get { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discounts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("discounts"); + return JsonModel.GetNotNullClass>(this.RawData, "discounts"); } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discounts", value); } } /// /// When the invoice payment is due. The due date is null if the invoice is not /// yet finalized. /// - public required System::DateTime? DueDate + public required System::DateTimeOffset? DueDate { get { - if (!this.Properties.TryGetValue("due_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "due_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "due_date"); } - set { this.Properties["due_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "due_date", value); } } /// @@ -366,24 +251,16 @@ public required string Currency /// will be eligible to be issued, otherwise it will be `null`. If `auto-issue` /// is true, the invoice will automatically begin issuing at this time. /// - public required System::DateTime? EligibleToIssueAt + public required System::DateTimeOffset? EligibleToIssueAt { get { - if (!this.Properties.TryGetValue("eligible_to_issue_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "eligible_to_issue_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["eligible_to_issue_at"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawData, + "eligible_to_issue_at" ); } + init { JsonModel.Set(this._rawData, "eligible_to_issue_at", value); } } /// @@ -392,20 +269,8 @@ public required string Currency /// public required string? HostedInvoiceURL { - get - { - if (!this.Properties.TryGetValue("hosted_invoice_url", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "hosted_invoice_url", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["hosted_invoice_url"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "hosted_invoice_url"); } + init { JsonModel.Set(this._rawData, "hosted_invoice_url", value); } } /// @@ -415,18 +280,8 @@ public required string? HostedInvoiceURL /// public required string InvoiceNumber { - get - { - if (!this.Properties.TryGetValue("invoice_number", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoice_number"); - } - set { this.Properties["invoice_number"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "invoice_number"); } + init { JsonModel.Set(this._rawData, "invoice_number", value); } } /// @@ -434,122 +289,75 @@ public required string InvoiceNumber /// public required string? InvoicePdf { - get - { - if (!this.Properties.TryGetValue("invoice_pdf", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_pdf", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice_pdf"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_pdf"); } + init { JsonModel.Set(this._rawData, "invoice_pdf", value); } } - public required InvoiceFetchUpcomingResponseProperties::InvoiceSource InvoiceSource + public required ApiEnum InvoiceSource { get { - if (!this.Properties.TryGetValue("invoice_source", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice_source", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("invoice_source"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "invoice_source"); } - set { this.Properties["invoice_source"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "invoice_source", value); } } /// /// If the invoice failed to issue, this will be the last time it failed to issue /// (even if it is now in a different state.) /// - public required System::DateTime? IssueFailedAt + public required System::DateTimeOffset? IssueFailedAt { get { - if (!this.Properties.TryGetValue("issue_failed_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "issue_failed_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawData, + "issue_failed_at" + ); } - set { this.Properties["issue_failed_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "issue_failed_at", value); } } /// - /// If the invoice has been issued, this will be the time it transitioned to `issued` - /// (even if it is now in a different state.) + /// If the invoice has been issued, this will be the time it transitioned to + /// `issued` (even if it is now in a different state.) /// - public required System::DateTime? IssuedAt + public required System::DateTimeOffset? IssuedAt { get { - if (!this.Properties.TryGetValue("issued_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "issued_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "issued_at"); } - set { this.Properties["issued_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "issued_at", value); } } /// /// The breakdown of prices in this invoice. /// - public required Generic::List LineItems + public required IReadOnlyList LineItems { get { - if (!this.Properties.TryGetValue("line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("line_items"); + return JsonModel.GetNotNullClass>( + this.RawData, + "line_items" + ); } - set { this.Properties["line_items"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "line_items", value); } } - public required Models::Maximum? Maximum + public required Maximum? Maximum { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } } public required string? MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// @@ -557,14 +365,8 @@ public required string? MaximumAmount /// public required string? Memo { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("memo", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } } /// @@ -573,209 +375,126 @@ public required string? Memo /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } - public required Models::Minimum? Minimum + public required Minimum? Minimum { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } } public required string? MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } /// /// If the invoice has a status of `paid`, this gives a timestamp when the invoice /// was paid. /// - public required System::DateTime? PaidAt + public required System::DateTimeOffset? PaidAt { - get - { - if (!this.Properties.TryGetValue("paid_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "paid_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["paid_at"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "paid_at"); } + init { JsonModel.Set(this._rawData, "paid_at", value); } } /// /// A list of payment attempts associated with the invoice /// - public required Generic::List PaymentAttempts + public required IReadOnlyList PaymentAttempts { get { - if (!this.Properties.TryGetValue("payment_attempts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_attempts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("payment_attempts"); - } - set - { - this.Properties["payment_attempts"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "payment_attempts" + ); } + init { JsonModel.Set(this._rawData, "payment_attempts", value); } } /// - /// If payment was attempted on this invoice but failed, this will be the time of - /// the most recent attempt. + /// If payment was attempted on this invoice but failed, this will be the time + /// of the most recent attempt. /// - public required System::DateTime? PaymentFailedAt + public required System::DateTimeOffset? PaymentFailedAt { get { - if (!this.Properties.TryGetValue("payment_failed_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_failed_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_failed_at"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "payment_failed_at" + ); } + init { JsonModel.Set(this._rawData, "payment_failed_at", value); } } /// - /// If payment was attempted on this invoice, this will be the start time of the - /// most recent attempt. This field is especially useful for delayed-notification + /// If payment was attempted on this invoice, this will be the start time of + /// the most recent attempt. This field is especially useful for delayed-notification /// payment mechanisms (like bank transfers), where payment can take 3 days or more. /// - public required System::DateTime? PaymentStartedAt + public required System::DateTimeOffset? PaymentStartedAt { get { - if (!this.Properties.TryGetValue("payment_started_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_started_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_started_at"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "payment_started_at" + ); } + init { JsonModel.Set(this._rawData, "payment_started_at", value); } } /// /// If the invoice is in draft, this timestamp will reflect when the invoice is /// scheduled to be issued. /// - public required System::DateTime? ScheduledIssueAt + public required System::DateTimeOffset? ScheduledIssueAt { get { - if (!this.Properties.TryGetValue("scheduled_issue_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "scheduled_issue_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["scheduled_issue_at"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "scheduled_issue_at" + ); } + init { JsonModel.Set(this._rawData, "scheduled_issue_at", value); } } - public required Models::Address? ShippingAddress + public required Address? ShippingAddress { - get - { - if (!this.Properties.TryGetValue("shipping_address", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "shipping_address", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["shipping_address"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass
(this.RawData, "shipping_address"); } + init { JsonModel.Set(this._rawData, "shipping_address", value); } } - public required InvoiceFetchUpcomingResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required Models::SubscriptionMinified? Subscription + public required SubscriptionMinified? Subscription { get { - if (!this.Properties.TryGetValue("subscription", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "subscription"); } - set { this.Properties["subscription"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "subscription", value); } } /// @@ -783,18 +502,8 @@ public required string? MinimumAmount /// public required string Subtotal { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } } /// @@ -802,37 +511,28 @@ public required string Subtotal /// provider sync was attempted. This field will always be `null` for invoices /// using Orb Invoicing. /// - public required System::DateTime? SyncFailedAt + public required System::DateTimeOffset? SyncFailedAt { get { - if (!this.Properties.TryGetValue("sync_failed_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "sync_failed_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawData, + "sync_failed_at" + ); } - set { this.Properties["sync_failed_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "sync_failed_at", value); } } /// /// The scheduled date of the invoice /// - public required System::DateTime TargetDate + public required System::DateTimeOffset TargetDate { get { - if (!this.Properties.TryGetValue("target_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "target_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "target_date"); } - set { this.Properties["target_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "target_date", value); } } /// @@ -840,34 +540,21 @@ public required string Subtotal /// public required string Total { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } } /// /// If the invoice has a status of `void`, this gives a timestamp when the invoice /// was voided. /// - public required System::DateTime? VoidedAt + public required System::DateTimeOffset? VoidedAt { get { - if (!this.Properties.TryGetValue("voided_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); } - set { this.Properties["voided_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "voided_at", value); } } /// @@ -876,19 +563,11 @@ public required string Total /// public required bool WillAutoIssue { - get - { - if (!this.Properties.TryGetValue("will_auto_issue", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "will_auto_issue", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["will_auto_issue"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "will_auto_issue"); } + init { JsonModel.Set(this._rawData, "will_auto_issue", value); } } + /// public override void Validate() { _ = this.ID; @@ -927,10 +606,7 @@ public override void Validate() this.Maximum?.Validate(); _ = this.MaximumAmount; _ = this.Memo; - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; this.Minimum?.Validate(); _ = this.MinimumAmount; _ = this.PaidAt; @@ -952,20 +628,1950 @@ public override void Validate() _ = this.WillAutoIssue; } + [System::Obsolete("Required properties are deprecated: discount")] public InvoiceFetchUpcomingResponse() { } + [System::Obsolete("Required properties are deprecated: discount")] + public InvoiceFetchUpcomingResponse(InvoiceFetchUpcomingResponse invoiceFetchUpcomingResponse) + : base(invoiceFetchUpcomingResponse) { } + + [System::Obsolete("Required properties are deprecated: discount")] + public InvoiceFetchUpcomingResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceFetchUpcomingResponse(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: discount")] + [SetsRequiredMembers] + InvoiceFetchUpcomingResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static InvoiceFetchUpcomingResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceFetchUpcomingResponseFromRaw : IFromRawJson +{ + /// + public InvoiceFetchUpcomingResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoiceFetchUpcomingResponse.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Invoices.AutoCollection, + global::Orb.Models.Invoices.AutoCollectionFromRaw + >) +)] +public sealed record class AutoCollection : JsonModel +{ + /// + /// True only if auto-collection is enabled for this invoice. + /// + public required bool? Enabled + { + get { return JsonModel.GetNullableStruct(this.RawData, "enabled"); } + init { JsonModel.Set(this._rawData, "enabled", value); } + } + + /// + /// If the invoice is scheduled for auto-collection, this field will reflect when + /// the next attempt will occur. If dunning has been exhausted, or auto-collection + /// is not enabled for this invoice, this field will be `null`. + /// + public required System::DateTimeOffset? NextAttemptAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "next_attempt_at" + ); + } + init { JsonModel.Set(this._rawData, "next_attempt_at", value); } + } + + /// + /// Number of auto-collection payment attempts. + /// + public required long? NumAttempts + { + get { return JsonModel.GetNullableStruct(this.RawData, "num_attempts"); } + init { JsonModel.Set(this._rawData, "num_attempts", value); } + } + + /// + /// If Orb has ever attempted payment auto-collection for this invoice, this field + /// will reflect when that attempt occurred. In conjunction with `next_attempt_at`, + /// this can be used to tell whether the invoice is currently in dunning (that + /// is, `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), + /// or if dunning has been exhausted (`previously_attempted_at` is non-null, but + /// `next_attempt_time` is null). + /// + public required System::DateTimeOffset? PreviouslyAttemptedAt + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "previously_attempted_at" + ); + } + init { JsonModel.Set(this._rawData, "previously_attempted_at", value); } + } + + /// + public override void Validate() + { + _ = this.Enabled; + _ = this.NextAttemptAt; + _ = this.NumAttempts; + _ = this.PreviouslyAttemptedAt; + } + + public AutoCollection() { } + + public AutoCollection(global::Orb.Models.Invoices.AutoCollection autoCollection) + : base(autoCollection) { } + + public AutoCollection(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AutoCollection(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Invoices.AutoCollection FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AutoCollectionFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Invoices.AutoCollection FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Invoices.AutoCollection.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Invoices.CreditNote, + global::Orb.Models.Invoices.CreditNoteFromRaw + >) +)] +public sealed record class CreditNote : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string CreditNoteNumber + { + get { return JsonModel.GetNotNullClass(this.RawData, "credit_note_number"); } + init { JsonModel.Set(this._rawData, "credit_note_number", value); } + } + + /// + /// An optional memo supplied on the credit note. + /// + public required string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + public required string Reason + { + get { return JsonModel.GetNotNullClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + public required string Total + { + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } + } + + public required string Type + { + get { return JsonModel.GetNotNullClass(this.RawData, "type"); } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + /// If the credit note has a status of `void`, this gives a timestamp when the + /// credit note was voided. + /// + public required System::DateTimeOffset? VoidedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); + } + init { JsonModel.Set(this._rawData, "voided_at", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CreditNoteNumber; + _ = this.Memo; + _ = this.Reason; + _ = this.Total; + _ = this.Type; + _ = this.VoidedAt; + } + + public CreditNote() { } + + public CreditNote(global::Orb.Models.Invoices.CreditNote creditNote) + : base(creditNote) { } + + public CreditNote(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CreditNote(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Invoices.CreditNote FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CreditNoteFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Invoices.CreditNote FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Invoices.CreditNote.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Invoices.CustomerBalanceTransaction, + global::Orb.Models.Invoices.CustomerBalanceTransactionFromRaw + >) +)] +public sealed record class CustomerBalanceTransaction : JsonModel +{ + /// + /// A unique id for this transaction. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required ApiEnum Action + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "action" + ); + } + init { JsonModel.Set(this._rawData, "action", value); } + } + + /// + /// The value of the amount changed in the transaction. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The creation time of this transaction. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required CreditNoteTiny? CreditNote + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_note"); } + init { JsonModel.Set(this._rawData, "credit_note", value); } + } + + /// + /// An optional description provided for manual customer balance adjustments. + /// + public required string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + /// + /// The new value of the customer's balance prior to the transaction, in the customer's currency. + /// + public required string EndingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "ending_balance"); } + init { JsonModel.Set(this._rawData, "ending_balance", value); } + } + + public required InvoiceTiny? Invoice + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice"); } + init { JsonModel.Set(this._rawData, "invoice", value); } + } + + /// + /// The original value of the customer's balance prior to the transaction, in + /// the customer's currency. + /// + public required string StartingBalance + { + get { return JsonModel.GetNotNullClass(this.RawData, "starting_balance"); } + init { JsonModel.Set(this._rawData, "starting_balance", value); } + } + + public required ApiEnum Type + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); + } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.Action.Validate(); + _ = this.Amount; + _ = this.CreatedAt; + this.CreditNote?.Validate(); + _ = this.Description; + _ = this.EndingBalance; + this.Invoice?.Validate(); + _ = this.StartingBalance; + this.Type.Validate(); + } + + public CustomerBalanceTransaction() { } + + public CustomerBalanceTransaction( + global::Orb.Models.Invoices.CustomerBalanceTransaction customerBalanceTransaction + ) + : base(customerBalanceTransaction) { } + + public CustomerBalanceTransaction(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CustomerBalanceTransaction(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Invoices.CustomerBalanceTransaction FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CustomerBalanceTransactionFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Invoices.CustomerBalanceTransaction FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Invoices.CustomerBalanceTransaction.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.ActionConverter))] +public enum Action +{ + AppliedToInvoice, + ManualAdjustment, + ProratedRefund, + RevertProratedRefund, + ReturnFromVoiding, + CreditNoteApplied, + CreditNoteVoided, + OverpaymentRefund, + ExternalPayment, + SmallInvoiceCarryover, +} + +sealed class ActionConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.Action Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "applied_to_invoice" => global::Orb.Models.Invoices.Action.AppliedToInvoice, + "manual_adjustment" => global::Orb.Models.Invoices.Action.ManualAdjustment, + "prorated_refund" => global::Orb.Models.Invoices.Action.ProratedRefund, + "revert_prorated_refund" => global::Orb.Models.Invoices.Action.RevertProratedRefund, + "return_from_voiding" => global::Orb.Models.Invoices.Action.ReturnFromVoiding, + "credit_note_applied" => global::Orb.Models.Invoices.Action.CreditNoteApplied, + "credit_note_voided" => global::Orb.Models.Invoices.Action.CreditNoteVoided, + "overpayment_refund" => global::Orb.Models.Invoices.Action.OverpaymentRefund, + "external_payment" => global::Orb.Models.Invoices.Action.ExternalPayment, + "small_invoice_carryover" => global::Orb.Models.Invoices.Action.SmallInvoiceCarryover, + _ => (global::Orb.Models.Invoices.Action)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.Action value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Invoices.Action.AppliedToInvoice => "applied_to_invoice", + global::Orb.Models.Invoices.Action.ManualAdjustment => "manual_adjustment", + global::Orb.Models.Invoices.Action.ProratedRefund => "prorated_refund", + global::Orb.Models.Invoices.Action.RevertProratedRefund => "revert_prorated_refund", + global::Orb.Models.Invoices.Action.ReturnFromVoiding => "return_from_voiding", + global::Orb.Models.Invoices.Action.CreditNoteApplied => "credit_note_applied", + global::Orb.Models.Invoices.Action.CreditNoteVoided => "credit_note_voided", + global::Orb.Models.Invoices.Action.OverpaymentRefund => "overpayment_refund", + global::Orb.Models.Invoices.Action.ExternalPayment => "external_payment", + global::Orb.Models.Invoices.Action.SmallInvoiceCarryover => + "small_invoice_carryover", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.TypeConverter))] +public enum Type +{ + Increment, + Decrement, +} + +sealed class TypeConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.Type Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "increment" => global::Orb.Models.Invoices.Type.Increment, + "decrement" => global::Orb.Models.Invoices.Type.Decrement, + _ => (global::Orb.Models.Invoices.Type)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.Type value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Invoices.Type.Increment => "increment", + global::Orb.Models.Invoices.Type.Decrement => "decrement", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.InvoiceSourceConverter))] +public enum InvoiceSource +{ + Subscription, + Partial, + OneOff, +} + +sealed class InvoiceSourceConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.InvoiceSource Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "subscription" => global::Orb.Models.Invoices.InvoiceSource.Subscription, + "partial" => global::Orb.Models.Invoices.InvoiceSource.Partial, + "one_off" => global::Orb.Models.Invoices.InvoiceSource.OneOff, + _ => (global::Orb.Models.Invoices.InvoiceSource)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.InvoiceSource value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Invoices.InvoiceSource.Subscription => "subscription", + global::Orb.Models.Invoices.InvoiceSource.Partial => "partial", + global::Orb.Models.Invoices.InvoiceSource.OneOff => "one_off", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + InvoiceFetchUpcomingResponseLineItem, + InvoiceFetchUpcomingResponseLineItemFromRaw + >) +)] +public sealed record class InvoiceFetchUpcomingResponseLineItem : JsonModel +{ + /// + /// A unique ID for this line item. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The line amount after any adjustments and before overage conversion, credits + /// and partial invoicing. + /// + public required string AdjustedSubtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjusted_subtotal"); } + init { JsonModel.Set(this._rawData, "adjusted_subtotal", value); } + } + + /// + /// All adjustments applied to the line item in the order they were applied based + /// on invoice calculations (ie. usage discounts -> amount discounts -> percentage + /// discounts -> minimums -> maximums). + /// + public required IReadOnlyList Adjustments + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustments" + ); + } + init { JsonModel.Set(this._rawData, "adjustments", value); } + } + + /// + /// The final amount for a line item after all adjustments and pre paid credits + /// have been applied. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The number of prepaid credits applied. + /// + public required string CreditsApplied + { + get { return JsonModel.GetNotNullClass(this.RawData, "credits_applied"); } + init { JsonModel.Set(this._rawData, "credits_applied", value); } + } + + /// + /// The end date of the range of time applied for this line item's price. + /// + public required System::DateTimeOffset EndDate + { + get { return JsonModel.GetNotNullStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// An additional filter that was used to calculate the usage for this line item. + /// + public required string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// [DEPRECATED] For configured prices that are split by a grouping key, this + /// will be populated with the key and a value. The `amount` and `subtotal` will + /// be the values for this particular grouping. + /// + public required string? Grouping + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } + } + + /// + /// The name of the price associated with this line item. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Any amount applied from a partial invoice + /// + public required string PartiallyInvoicedAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "partially_invoiced_amount"); } + init { JsonModel.Set(this._rawData, "partially_invoiced_amount", value); } + } + + /// + /// The Price resource represents a price that can be billed on a subscription, + /// resulting in a charge on an invoice in the form of an invoice line item. + /// Prices take a quantity and determine an amount to bill. + /// + /// Orb supports a few different pricing models out of the box. Each of + /// these models is serialized differently in a given Price object. The model_type + /// field determines the key for the configuration object that is present. + /// + /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + /// + public required Price Price + { + get { return JsonModel.GetNotNullClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// Either the fixed fee quantity or the usage during the service period. + /// + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + /// The start date of the range of time applied for this line item's price. + /// + public required System::DateTimeOffset StartDate + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); + } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + /// For complex pricing structures, the line item can be broken down further + /// in `sub_line_items`. + /// + public required IReadOnlyList SubLineItems + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "sub_line_items" + ); + } + init { JsonModel.Set(this._rawData, "sub_line_items", value); } + } + + /// + /// The line amount before any adjustments. + /// + public required string Subtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } + + /// + /// An array of tax rates and their incurred tax amounts. Empty if no tax integration + /// is configured. + /// + public required IReadOnlyList TaxAmounts + { + get { return JsonModel.GetNotNullClass>(this.RawData, "tax_amounts"); } + init { JsonModel.Set(this._rawData, "tax_amounts", value); } + } + + /// + /// A list of customer ids that were used to calculate the usage for this line item. + /// + public required IReadOnlyList? UsageCustomerIDs + { + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.AdjustedSubtotal; + foreach (var item in this.Adjustments) + { + item.Validate(); + } + _ = this.Amount; + _ = this.CreditsApplied; + _ = this.EndDate; + _ = this.Filter; + _ = this.Grouping; + _ = this.Name; + _ = this.PartiallyInvoicedAmount; + this.Price.Validate(); + _ = this.Quantity; + _ = this.StartDate; + foreach (var item in this.SubLineItems) + { + item.Validate(); + } + _ = this.Subtotal; + foreach (var item in this.TaxAmounts) + { + item.Validate(); + } + _ = this.UsageCustomerIDs; + } + + public InvoiceFetchUpcomingResponseLineItem() { } + + public InvoiceFetchUpcomingResponseLineItem( + InvoiceFetchUpcomingResponseLineItem invoiceFetchUpcomingResponseLineItem + ) + : base(invoiceFetchUpcomingResponseLineItem) { } + + public InvoiceFetchUpcomingResponseLineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceFetchUpcomingResponseLineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceFetchUpcomingResponseLineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class InvoiceFetchUpcomingResponseLineItemFromRaw + : IFromRawJson +{ + /// + public InvoiceFetchUpcomingResponseLineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoiceFetchUpcomingResponseLineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.AdjustmentConverter))] +public record class Adjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ID, + monetaryAmountDiscount: (x) => x.ID, + monetaryPercentageDiscount: (x) => x.ID, + monetaryMinimum: (x) => x.ID, + monetaryMaximum: (x) => x.ID + ); + } + } + + public string Amount + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.Amount, + monetaryAmountDiscount: (x) => x.Amount, + monetaryPercentageDiscount: (x) => x.Amount, + monetaryMinimum: (x) => x.Amount, + monetaryMaximum: (x) => x.Amount + ); + } + } + + public bool IsInvoiceLevel + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.IsInvoiceLevel, + monetaryAmountDiscount: (x) => x.IsInvoiceLevel, + monetaryPercentageDiscount: (x) => x.IsInvoiceLevel, + monetaryMinimum: (x) => x.IsInvoiceLevel, + monetaryMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public string? Reason + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.Reason, + monetaryAmountDiscount: (x) => x.Reason, + monetaryPercentageDiscount: (x) => x.Reason, + monetaryMinimum: (x) => x.Reason, + monetaryMaximum: (x) => x.Reason + ); + } + } + + public string? ReplacesAdjustmentID + { + get + { + return Match( + monetaryUsageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryAmountDiscount: (x) => x.ReplacesAdjustmentID, + monetaryPercentageDiscount: (x) => x.ReplacesAdjustmentID, + monetaryMinimum: (x) => x.ReplacesAdjustmentID, + monetaryMaximum: (x) => x.ReplacesAdjustmentID + ); + } + } + + public Adjustment(MonetaryUsageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryAmountDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryPercentageDiscountAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryMinimumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(MonetaryMaximumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryUsageDiscount(out var value)) { + /// // `value` is of type `MonetaryUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryUsageDiscount( + [NotNullWhen(true)] out MonetaryUsageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryUsageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryAmountDiscount(out var value)) { + /// // `value` is of type `MonetaryAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryAmountDiscount( + [NotNullWhen(true)] out MonetaryAmountDiscountAdjustment? value + ) + { + value = this.Value as MonetaryAmountDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryPercentageDiscount(out var value)) { + /// // `value` is of type `MonetaryPercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryPercentageDiscount( + [NotNullWhen(true)] out MonetaryPercentageDiscountAdjustment? value + ) + { + value = this.Value as MonetaryPercentageDiscountAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMinimum(out var value)) { + /// // `value` is of type `MonetaryMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMinimum([NotNullWhen(true)] out MonetaryMinimumAdjustment? value) + { + value = this.Value as MonetaryMinimumAdjustment; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMonetaryMaximum(out var value)) { + /// // `value` is of type `MonetaryMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMonetaryMaximum([NotNullWhen(true)] out MonetaryMaximumAdjustment? value) + { + value = this.Value as MonetaryMaximumAdjustment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action monetaryUsageDiscount, + System::Action monetaryAmountDiscount, + System::Action monetaryPercentageDiscount, + System::Action monetaryMinimum, + System::Action monetaryMaximum + ) + { + switch (this.Value) + { + case MonetaryUsageDiscountAdjustment value: + monetaryUsageDiscount(value); + break; + case MonetaryAmountDiscountAdjustment value: + monetaryAmountDiscount(value); + break; + case MonetaryPercentageDiscountAdjustment value: + monetaryPercentageDiscount(value); + break; + case MonetaryMinimumAdjustment value: + monetaryMinimum(value); + break; + case MonetaryMaximumAdjustment value: + monetaryMaximum(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MonetaryUsageDiscountAdjustment value) => {...}, + /// (MonetaryAmountDiscountAdjustment value) => {...}, + /// (MonetaryPercentageDiscountAdjustment value) => {...}, + /// (MonetaryMinimumAdjustment value) => {...}, + /// (MonetaryMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func monetaryUsageDiscount, + System::Func monetaryAmountDiscount, + System::Func monetaryPercentageDiscount, + System::Func monetaryMinimum, + System::Func monetaryMaximum + ) + { + return this.Value switch + { + MonetaryUsageDiscountAdjustment value => monetaryUsageDiscount(value), + MonetaryAmountDiscountAdjustment value => monetaryAmountDiscount(value), + MonetaryPercentageDiscountAdjustment value => monetaryPercentageDiscount(value), + MonetaryMinimumAdjustment value => monetaryMinimum(value), + MonetaryMaximumAdjustment value => monetaryMaximum(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Adjustment"), + }; + } + + public static implicit operator global::Orb.Models.Invoices.Adjustment( + MonetaryUsageDiscountAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.Invoices.Adjustment( + MonetaryAmountDiscountAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.Invoices.Adjustment( + MonetaryPercentageDiscountAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.Invoices.Adjustment( + MonetaryMinimumAdjustment value + ) => new(value); + + public static implicit operator global::Orb.Models.Invoices.Adjustment( + MonetaryMaximumAdjustment value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + this.Switch( + (monetaryUsageDiscount) => monetaryUsageDiscount.Validate(), + (monetaryAmountDiscount) => monetaryAmountDiscount.Validate(), + (monetaryPercentageDiscount) => monetaryPercentageDiscount.Validate(), + (monetaryMinimum) => monetaryMinimum.Validate(), + (monetaryMaximum) => monetaryMaximum.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Invoices.Adjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.Adjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Invoices.Adjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.Adjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.SubLineItemConverter))] +public record class SubLineItem +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Amount + { + get + { + return Match(matrix: (x) => x.Amount, tier: (x) => x.Amount, other: (x) => x.Amount); + } + } + + public SubLineItemGrouping? Grouping + { + get + { + return Match( + matrix: (x) => x.Grouping, + tier: (x) => x.Grouping, + other: (x) => x.Grouping + ); + } + } + + public string Name + { + get { return Match(matrix: (x) => x.Name, tier: (x) => x.Name, other: (x) => x.Name); } + } + + public double Quantity + { + get + { + return Match( + matrix: (x) => x.Quantity, + tier: (x) => x.Quantity, + other: (x) => x.Quantity + ); + } + } + + public SubLineItem(MatrixSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(TierSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(OtherSubLineItem value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubLineItem(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrix(out var value)) { + /// // `value` is of type `MatrixSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrix([NotNullWhen(true)] out MatrixSubLineItem? value) + { + value = this.Value as MatrixSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTier(out var value)) { + /// // `value` is of type `TierSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTier([NotNullWhen(true)] out TierSubLineItem? value) + { + value = this.Value as TierSubLineItem; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickOther(out var value)) { + /// // `value` is of type `OtherSubLineItem` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickOther([NotNullWhen(true)] out OtherSubLineItem? value) + { + value = this.Value as OtherSubLineItem; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action matrix, + System::Action tier, + System::Action other + ) + { + switch (this.Value) + { + case MatrixSubLineItem value: + matrix(value); + break; + case TierSubLineItem value: + tier(value); + break; + case OtherSubLineItem value: + other(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (MatrixSubLineItem value) => {...}, + /// (TierSubLineItem value) => {...}, + /// (OtherSubLineItem value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func matrix, + System::Func tier, + System::Func other + ) + { + return this.Value switch + { + MatrixSubLineItem value => matrix(value), + TierSubLineItem value => tier(value), + OtherSubLineItem value => other(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"), + }; + } + + public static implicit operator global::Orb.Models.Invoices.SubLineItem( + MatrixSubLineItem value + ) => new(value); + + public static implicit operator global::Orb.Models.Invoices.SubLineItem( + TierSubLineItem value + ) => new(value); + + public static implicit operator global::Orb.Models.Invoices.SubLineItem( + OtherSubLineItem value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of SubLineItem"); + } + this.Switch( + (matrix) => matrix.Validate(), + (tier) => tier.Validate(), + (other) => other.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Invoices.SubLineItem? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubLineItemConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.SubLineItem? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? type; + try + { + type = element.GetProperty("type").GetString(); + } + catch + { + type = null; + } + + switch (type) + { + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tier": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "'null'": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Invoices.SubLineItem(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.SubLineItem value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Invoices.PaymentAttempt, + global::Orb.Models.Invoices.PaymentAttemptFromRaw + >) +)] +public sealed record class PaymentAttempt : JsonModel +{ + /// + /// The ID of the payment attempt. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The amount of the payment attempt. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The time at which the payment attempt was created. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + /// + /// The payment provider that attempted to collect the payment. + /// + public required ApiEnum? PaymentProvider + { + get + { + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "payment_provider"); + } + init { JsonModel.Set(this._rawData, "payment_provider", value); } + } + + /// + /// The ID of the payment attempt in the payment provider. + /// + public required string? PaymentProviderID + { + get { return JsonModel.GetNullableClass(this.RawData, "payment_provider_id"); } + init { JsonModel.Set(this._rawData, "payment_provider_id", value); } + } + + /// + /// URL to the downloadable PDF version of the receipt. This field will be `null` + /// for payment attempts that did not succeed. + /// + public required string? ReceiptPdf + { + get { return JsonModel.GetNullableClass(this.RawData, "receipt_pdf"); } + init { JsonModel.Set(this._rawData, "receipt_pdf", value); } + } + + /// + /// Whether the payment attempt succeeded. + /// + public required bool Succeeded + { + get { return JsonModel.GetNotNullStruct(this.RawData, "succeeded"); } + init { JsonModel.Set(this._rawData, "succeeded", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Amount; + _ = this.CreatedAt; + this.PaymentProvider?.Validate(); + _ = this.PaymentProviderID; + _ = this.ReceiptPdf; + _ = this.Succeeded; + } + + public PaymentAttempt() { } + + public PaymentAttempt(global::Orb.Models.Invoices.PaymentAttempt paymentAttempt) + : base(paymentAttempt) { } + + public PaymentAttempt(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PaymentAttempt(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Invoices.PaymentAttempt FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PaymentAttemptFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Invoices.PaymentAttempt FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Invoices.PaymentAttempt.FromRawUnchecked(rawData); +} + +/// +/// The payment provider that attempted to collect the payment. +/// +[JsonConverter(typeof(global::Orb.Models.Invoices.PaymentProviderConverter))] +public enum PaymentProvider +{ + Stripe, +} + +sealed class PaymentProviderConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.PaymentProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => global::Orb.Models.Invoices.PaymentProvider.Stripe, + _ => (global::Orb.Models.Invoices.PaymentProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.PaymentProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Invoices.PaymentProvider.Stripe => "stripe", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(InvoiceFetchUpcomingResponseStatusConverter))] +public enum InvoiceFetchUpcomingResponseStatus +{ + Issued, + Paid, + Synced, + Void, + Draft, +} + +sealed class InvoiceFetchUpcomingResponseStatusConverter + : JsonConverter +{ + public override InvoiceFetchUpcomingResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "issued" => InvoiceFetchUpcomingResponseStatus.Issued, + "paid" => InvoiceFetchUpcomingResponseStatus.Paid, + "synced" => InvoiceFetchUpcomingResponseStatus.Synced, + "void" => InvoiceFetchUpcomingResponseStatus.Void, + "draft" => InvoiceFetchUpcomingResponseStatus.Draft, + _ => (InvoiceFetchUpcomingResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceFetchUpcomingResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + InvoiceFetchUpcomingResponseStatus.Issued => "issued", + InvoiceFetchUpcomingResponseStatus.Paid => "paid", + InvoiceFetchUpcomingResponseStatus.Synced => "synced", + InvoiceFetchUpcomingResponseStatus.Void => "void", + InvoiceFetchUpcomingResponseStatus.Draft => "draft", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/AutoCollection.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/AutoCollection.cs deleted file mode 100644 index ad180830..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/AutoCollection.cs +++ /dev/null @@ -1,126 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AutoCollection : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// True only if auto-collection is enabled for this invoice. - /// - public required bool? Enabled - { - get - { - if (!this.Properties.TryGetValue("enabled", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "enabled", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["enabled"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If the invoice is scheduled for auto-collection, this field will reflect when - /// the next attempt will occur. If dunning has been exhausted, or auto-collection - /// is not enabled for this invoice, this field will be `null`. - /// - public required System::DateTime? NextAttemptAt - { - get - { - if (!this.Properties.TryGetValue("next_attempt_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "next_attempt_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["next_attempt_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Number of auto-collection payment attempts. - /// - public required long? NumAttempts - { - get - { - if (!this.Properties.TryGetValue("num_attempts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "num_attempts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["num_attempts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If Orb has ever attempted payment auto-collection for this invoice, this field - /// will reflect when that attempt occurred. In conjunction with `next_attempt_at`, - /// this can be used to tell whether the invoice is currently in dunning (that is, - /// `previously_attempted_at` is non-null, and `next_attempt_time` is non-null), - /// or if dunning has been exhausted (`previously_attempted_at` is non-null, but - /// `next_attempt_time` is null). - /// - public required System::DateTime? PreviouslyAttemptedAt - { - get - { - if ( - !this.Properties.TryGetValue( - "previously_attempted_at", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "previously_attempted_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["previously_attempted_at"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.Enabled; - _ = this.NextAttemptAt; - _ = this.NumAttempts; - _ = this.PreviouslyAttemptedAt; - } - - public AutoCollection() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AutoCollection(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AutoCollection FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CreditNote.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CreditNote.cs deleted file mode 100644 index 6733402e..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CreditNote.cs +++ /dev/null @@ -1,148 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CreditNote : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string CreditNoteNumber - { - get - { - if (!this.Properties.TryGetValue("credit_note_number", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note_number", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credit_note_number"); - } - set - { - this.Properties["credit_note_number"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An optional memo supplied on the credit note. - /// - public required string? Memo - { - get - { - if (!this.Properties.TryGetValue("memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("memo", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["memo"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Reason - { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("reason"); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Total - { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Type - { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// If the credit note has a status of `void`, this gives a timestamp when the - /// credit note was voided. - /// - public required System::DateTime? VoidedAt - { - get - { - if (!this.Properties.TryGetValue("voided_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "voided_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["voided_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.CreditNoteNumber; - _ = this.Memo; - _ = this.Reason; - _ = this.Total; - _ = this.Type; - _ = this.VoidedAt; - } - - public CreditNote() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CreditNote(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static CreditNote FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransaction.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransaction.cs deleted file mode 100644 index 9911dff2..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransaction.cs +++ /dev/null @@ -1,221 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CustomerBalanceTransactionProperties = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.CustomerBalanceTransactionProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CustomerBalanceTransaction - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// A unique id for this transaction. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required CustomerBalanceTransactionProperties::Action Action - { - get - { - if (!this.Properties.TryGetValue("action", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "action", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("action"); - } - set { this.Properties["action"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The value of the amount changed in the transaction. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The creation time of this transaction. - /// - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::CreditNoteTiny? CreditNote - { - get - { - if (!this.Properties.TryGetValue("credit_note", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_note", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["credit_note"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional description provided for manual customer balance adjustments. - /// - public required string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The new value of the customer's balance prior to the transaction, in the customer's currency. - /// - public required string EndingBalance - { - get - { - if (!this.Properties.TryGetValue("ending_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "ending_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("ending_balance"); - } - set { this.Properties["ending_balance"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::InvoiceTiny? Invoice - { - get - { - if (!this.Properties.TryGetValue("invoice", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoice", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["invoice"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The original value of the customer's balance prior to the transaction, in the - /// customer's currency. - /// - public required string StartingBalance - { - get - { - if (!this.Properties.TryGetValue("starting_balance", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "starting_balance", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("starting_balance"); - } - set - { - this.Properties["starting_balance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required CustomerBalanceTransactionProperties::Type Type - { - get - { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("type"); - } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - this.Action.Validate(); - _ = this.Amount; - _ = this.CreatedAt; - this.CreditNote?.Validate(); - _ = this.Description; - _ = this.EndingBalance; - this.Invoice?.Validate(); - _ = this.StartingBalance; - this.Type.Validate(); - } - - public CustomerBalanceTransaction() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CustomerBalanceTransaction(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static CustomerBalanceTransaction FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransactionProperties/Action.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransactionProperties/Action.cs deleted file mode 100644 index b7364296..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransactionProperties/Action.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.CustomerBalanceTransactionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Action(string value) : Orb::IEnum -{ - public static readonly Action AppliedToInvoice = new("applied_to_invoice"); - - public static readonly Action ManualAdjustment = new("manual_adjustment"); - - public static readonly Action ProratedRefund = new("prorated_refund"); - - public static readonly Action RevertProratedRefund = new("revert_prorated_refund"); - - public static readonly Action ReturnFromVoiding = new("return_from_voiding"); - - public static readonly Action CreditNoteApplied = new("credit_note_applied"); - - public static readonly Action CreditNoteVoided = new("credit_note_voided"); - - public static readonly Action OverpaymentRefund = new("overpayment_refund"); - - public static readonly Action ExternalPayment = new("external_payment"); - - readonly string _value = value; - - public enum Value - { - AppliedToInvoice, - ManualAdjustment, - ProratedRefund, - RevertProratedRefund, - ReturnFromVoiding, - CreditNoteApplied, - CreditNoteVoided, - OverpaymentRefund, - ExternalPayment, - } - - public Value Known() => - _value switch - { - "applied_to_invoice" => Value.AppliedToInvoice, - "manual_adjustment" => Value.ManualAdjustment, - "prorated_refund" => Value.ProratedRefund, - "revert_prorated_refund" => Value.RevertProratedRefund, - "return_from_voiding" => Value.ReturnFromVoiding, - "credit_note_applied" => Value.CreditNoteApplied, - "credit_note_voided" => Value.CreditNoteVoided, - "overpayment_refund" => Value.OverpaymentRefund, - "external_payment" => Value.ExternalPayment, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Action FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransactionProperties/Type.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransactionProperties/Type.cs deleted file mode 100644 index b5cc69e4..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/CustomerBalanceTransactionProperties/Type.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.CustomerBalanceTransactionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Increment = new("increment"); - - public static readonly Type Decrement = new("decrement"); - - readonly string _value = value; - - public enum Value - { - Increment, - Decrement, - } - - public Value Known() => - _value switch - { - "increment" => Value.Increment, - "decrement" => Value.Decrement, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/InvoiceSource.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/InvoiceSource.cs deleted file mode 100644 index ce1f281f..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/InvoiceSource.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class InvoiceSource(string value) : Orb::IEnum -{ - public static readonly InvoiceSource Subscription = new("subscription"); - - public static readonly InvoiceSource Partial = new("partial"); - - public static readonly InvoiceSource OneOff = new("one_off"); - - readonly string _value = value; - - public enum Value - { - Subscription, - Partial, - OneOff, - } - - public Value Known() => - _value switch - { - "subscription" => Value.Subscription, - "partial" => Value.Partial, - "one_off" => Value.OneOff, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static InvoiceSource FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItem.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItem.cs deleted file mode 100644 index b8954e9f..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItem.cs +++ /dev/null @@ -1,500 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using LineItemProperties = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class LineItem : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A unique ID for this line item. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The line amount after any adjustments and before overage conversion, credits - /// and partial invoicing. - /// - public required string AdjustedSubtotal - { - get - { - if (!this.Properties.TryGetValue("adjusted_subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjusted_subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjusted_subtotal"); - } - set - { - this.Properties["adjusted_subtotal"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// All adjustments applied to the line item in the order they were applied based - /// on invoice calculations (ie. usage discounts -> amount discounts -> percentage - /// discounts -> minimums -> maximums). - /// - public required Generic::List Adjustments - { - get - { - if (!this.Properties.TryGetValue("adjustments", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustments", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustments"); - } - set { this.Properties["adjustments"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The final amount for a line item after all adjustments and pre paid credits - /// have been applied. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The number of prepaid credits applied. - /// - public required string CreditsApplied - { - get - { - if (!this.Properties.TryGetValue("credits_applied", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credits_applied", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("credits_applied"); - } - set { this.Properties["credits_applied"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments` - /// - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the range of time applied for this line item's price. - /// - public required System::DateTime EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An additional filter that was used to calculate the usage for this line item. - /// - public required string? Filter - { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filter", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// [DEPRECATED] For configured prices that are split by a grouping key, this will - /// be populated with the key and a value. The `amount` and `subtotal` will be - /// the values for this particular grouping. - /// - public required string? Grouping - { - get - { - if (!this.Properties.TryGetValue("grouping", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["grouping"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// This field is deprecated in favor of `adjustments`. - /// - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price associated with this line item. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Any amount applied from a partial invoice - /// - public required string PartiallyInvoicedAmount - { - get - { - if ( - !this.Properties.TryGetValue( - "partially_invoiced_amount", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "partially_invoiced_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("partially_invoiced_amount"); - } - set - { - this.Properties["partially_invoiced_amount"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The Price resource represents a price that can be billed on a subscription, - /// resulting in a charge on an invoice in the form of an invoice line item. Prices - /// take a quantity and determine an amount to bill. - /// - /// Orb supports a few different pricing models out of the box. Each of these models - /// is serialized differently in a given Price object. The model_type field determines - /// the key for the configuration object that is present. - /// - /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) - /// - public required Models::Price Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("price", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price"); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Either the fixed fee quantity or the usage during the service period. - /// - public required double Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The start date of the range of time applied for this line item's price. - /// - public required System::DateTime StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For complex pricing structures, the line item can be broken down further in `sub_line_items`. - /// - public required Generic::List SubLineItems - { - get - { - if (!this.Properties.TryGetValue("sub_line_items", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "sub_line_items", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("sub_line_items"); - } - set { this.Properties["sub_line_items"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The line amount before before any adjustments. - /// - public required string Subtotal - { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An array of tax rates and their incurred tax amounts. Empty if no tax integration - /// is configured. - /// - public required Generic::List TaxAmounts - { - get - { - if (!this.Properties.TryGetValue("tax_amounts", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_amounts", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tax_amounts"); - } - set { this.Properties["tax_amounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A list of customer ids that were used to calculate the usage for this line item. - /// - public required Generic::List? UsageCustomerIDs - { - get - { - if (!this.Properties.TryGetValue("usage_customer_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_customer_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - _ = this.AdjustedSubtotal; - foreach (var item in this.Adjustments) - { - item.Validate(); - } - _ = this.Amount; - _ = this.CreditsApplied; - this.Discount?.Validate(); - _ = this.EndDate; - _ = this.Filter; - _ = this.Grouping; - this.Maximum?.Validate(); - _ = this.MaximumAmount; - this.Minimum?.Validate(); - _ = this.MinimumAmount; - _ = this.Name; - _ = this.PartiallyInvoicedAmount; - this.Price.Validate(); - _ = this.Quantity; - _ = this.StartDate; - foreach (var item in this.SubLineItems) - { - item.Validate(); - } - _ = this.Subtotal; - foreach (var item in this.TaxAmounts) - { - item.Validate(); - } - foreach (var item in this.UsageCustomerIDs ?? []) - { - _ = item; - } - } - - public LineItem() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - LineItem(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static LineItem FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/Adjustment.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/Adjustment.cs deleted file mode 100644 index 25df9180..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/Adjustment.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AdjustmentVariants = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::MonetaryUsageDiscountAdjustment Create( - Models::MonetaryUsageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryAmountDiscountAdjustment Create( - Models::MonetaryAmountDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryPercentageDiscountAdjustment Create( - Models::MonetaryPercentageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryMinimumAdjustment Create( - Models::MonetaryMinimumAdjustment value - ) => new(value); - - public static AdjustmentVariants::MonetaryMaximumAdjustment Create( - Models::MonetaryMaximumAdjustment value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 12ad7673..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,120 +0,0 @@ -using LineItemProperties = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryUsageDiscountAdjustment, - Models::MonetaryUsageDiscountAdjustment - >) -)] -public sealed record class MonetaryUsageDiscountAdjustment( - Models::MonetaryUsageDiscountAdjustment Value -) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryUsageDiscountAdjustment From( - Models::MonetaryUsageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryAmountDiscountAdjustment, - Models::MonetaryAmountDiscountAdjustment - >) -)] -public sealed record class MonetaryAmountDiscountAdjustment( - Models::MonetaryAmountDiscountAdjustment Value -) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryAmountDiscountAdjustment From( - Models::MonetaryAmountDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - MonetaryPercentageDiscountAdjustment, - Models::MonetaryPercentageDiscountAdjustment - >) -)] -public sealed record class MonetaryPercentageDiscountAdjustment( - Models::MonetaryPercentageDiscountAdjustment Value -) - : LineItemProperties::Adjustment, - Orb::IVariant< - MonetaryPercentageDiscountAdjustment, - Models::MonetaryPercentageDiscountAdjustment - > -{ - public static MonetaryPercentageDiscountAdjustment From( - Models::MonetaryPercentageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MonetaryMinimumAdjustment(Models::MonetaryMinimumAdjustment Value) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryMinimumAdjustment From(Models::MonetaryMinimumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MonetaryMaximumAdjustment(Models::MonetaryMaximumAdjustment Value) - : LineItemProperties::Adjustment, - Orb::IVariant -{ - public static MonetaryMaximumAdjustment From(Models::MonetaryMaximumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/SubLineItem.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/SubLineItem.cs deleted file mode 100644 index 1f8142e4..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/SubLineItem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubLineItemVariants = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties.SubLineItemVariants; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class SubLineItem -{ - internal SubLineItem() { } - - public static SubLineItemVariants::MatrixSubLineItem Create(Models::MatrixSubLineItem value) => - new(value); - - public static SubLineItemVariants::TierSubLineItem Create(Models::TierSubLineItem value) => - new(value); - - public static SubLineItemVariants::OtherSubLineItem Create(Models::OtherSubLineItem value) => - new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/SubLineItemVariants/All.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/SubLineItemVariants/All.cs deleted file mode 100644 index d362c779..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/LineItemProperties/SubLineItemVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using LineItemProperties = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.LineItemProperties.SubLineItemVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MatrixSubLineItem(Models::MatrixSubLineItem Value) - : LineItemProperties::SubLineItem, - Orb::IVariant -{ - public static MatrixSubLineItem From(Models::MatrixSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TierSubLineItem(Models::TierSubLineItem Value) - : LineItemProperties::SubLineItem, - Orb::IVariant -{ - public static TierSubLineItem From(Models::TierSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class OtherSubLineItem(Models::OtherSubLineItem Value) - : LineItemProperties::SubLineItem, - Orb::IVariant -{ - public static OtherSubLineItem From(Models::OtherSubLineItem value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/PaymentAttempt.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/PaymentAttempt.cs deleted file mode 100644 index 5eb9cd5f..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/PaymentAttempt.cs +++ /dev/null @@ -1,155 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PaymentAttemptProperties = Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.PaymentAttemptProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PaymentAttempt : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The ID of the payment attempt. - /// - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The amount of the payment attempt. - /// - public required string Amount - { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The time at which the payment attempt was created. - /// - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The payment provider that attempted to collect the payment. - /// - public required PaymentAttemptProperties::PaymentProvider? PaymentProvider - { - get - { - if (!this.Properties.TryGetValue("payment_provider", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_provider", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["payment_provider"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The ID of the payment attempt in the payment provider. - /// - public required string? PaymentProviderID - { - get - { - if (!this.Properties.TryGetValue("payment_provider_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "payment_provider_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["payment_provider_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// Whether the payment attempt succeeded. - /// - public required bool Succeeded - { - get - { - if (!this.Properties.TryGetValue("succeeded", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "succeeded", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["succeeded"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Amount; - _ = this.CreatedAt; - this.PaymentProvider?.Validate(); - _ = this.PaymentProviderID; - _ = this.Succeeded; - } - - public PaymentAttempt() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PaymentAttempt(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PaymentAttempt FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/PaymentAttemptProperties/PaymentProvider.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/PaymentAttemptProperties/PaymentProvider.cs deleted file mode 100644 index 23349cdd..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/PaymentAttemptProperties/PaymentProvider.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties.PaymentAttemptProperties; - -/// -/// The payment provider that attempted to collect the payment. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PaymentProvider(string value) : Orb::IEnum -{ - public static readonly PaymentProvider Stripe = new("stripe"); - - readonly string _value = value; - - public enum Value - { - Stripe, - } - - public Value Known() => - _value switch - { - "stripe" => Value.Stripe, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PaymentProvider FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/Status.cs b/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/Status.cs deleted file mode 100644 index 7b9371a7..00000000 --- a/src/Orb/Models/Invoices/InvoiceFetchUpcomingResponseProperties/Status.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceFetchUpcomingResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Issued = new("issued"); - - public static readonly Status Paid = new("paid"); - - public static readonly Status Synced = new("synced"); - - public static readonly Status Void = new("void"); - - public static readonly Status Draft = new("draft"); - - readonly string _value = value; - - public enum Value - { - Issued, - Paid, - Synced, - Void, - Draft, - } - - public Value Known() => - _value switch - { - "issued" => Value.Issued, - "paid" => Value.Paid, - "synced" => Value.Synced, - "void" => Value.Void, - "draft" => Value.Draft, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceIssueParams.cs b/src/Orb/Models/Invoices/InvoiceIssueParams.cs index 09969b8f..b5079376 100644 --- a/src/Orb/Models/Invoices/InvoiceIssueParams.cs +++ b/src/Orb/Models/Invoices/InvoiceIssueParams.cs @@ -1,70 +1,125 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Invoices; /// -/// This endpoint allows an eligible invoice to be issued manually. This is only -/// possible with invoices where status is `draft`, `will_auto_issue` is false, and -/// an `eligible_to_issue_at` is a time in the past. Issuing an invoice could possibly -/// trigger side effects, some of which could be customer-visible (e.g. sending emails, -/// auto-collecting payment, syncing the invoice to external providers, etc). +/// This endpoint allows an eligible invoice to be issued manually. This is only possible +/// with invoices where status is `draft`, `will_auto_issue` is false, and an `eligible_to_issue_at` +/// is a time in the past. Issuing an invoice could possibly trigger side effects, +/// some of which could be customer-visible (e.g. sending emails, auto-collecting +/// payment, syncing the invoice to external providers, etc). /// -public sealed record class InvoiceIssueParams : Orb::ParamsBase +public sealed record class InvoiceIssueParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string InvoiceID; + public string? InvoiceID { get; init; } /// - /// If true, the invoice will be issued synchronously. If false, the invoice will - /// be issued asynchronously. The synchronous option is only available for invoices - /// that have no usage fees. If the invoice is configured to sync to an external - /// provider, a successful response from this endpoint guarantees the invoice is - /// present in the provider. + /// If true, the invoice will be issued synchronously. If false, the invoice + /// will be issued asynchronously. The synchronous option is only available for + /// invoices that have no usage fees. If the invoice is configured to sync to + /// an external provider, a successful response from this endpoint guarantees + /// the invoice is present in the provider. /// public bool? Synchronous { - get + get { return JsonModel.GetNullableStruct(this.RawBodyData, "synchronous"); } + init { - if (!this.BodyProperties.TryGetValue("synchronous", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawBodyData, "synchronous", value); } - set { this.BodyProperties["synchronous"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public InvoiceIssueParams() { } + + public InvoiceIssueParams(InvoiceIssueParams invoiceIssueParams) + : base(invoiceIssueParams) + { + this._rawBodyData = [.. invoiceIssueParams._rawBodyData]; + } + + public InvoiceIssueParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceIssueParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceIssueParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}/issue", this.InvoiceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Invoices/InvoiceListPage.cs b/src/Orb/Models/Invoices/InvoiceListPage.cs new file mode 100644 index 00000000..2d693778 --- /dev/null +++ b/src/Orb/Models/Invoices/InvoiceListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Invoices; + +public sealed class InvoiceListPage( + IInvoiceService service, + InvoiceListParams parameters, + InvoiceListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Invoices/InvoiceListPageResponse.cs b/src/Orb/Models/Invoices/InvoiceListPageResponse.cs index 9d5f9de9..528352f8 100644 --- a/src/Orb/Models/Invoices/InvoiceListPageResponse.cs +++ b/src/Orb/Models/Invoices/InvoiceListPageResponse.cs @@ -1,50 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Invoices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class InvoiceListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class InvoiceListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +40,35 @@ public override void Validate() public InvoiceListPageResponse() { } + public InvoiceListPageResponse(InvoiceListPageResponse invoiceListPageResponse) + : base(invoiceListPageResponse) { } + + public InvoiceListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - InvoiceListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + InvoiceListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static InvoiceListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class InvoiceListPageResponseFromRaw : IFromRawJson +{ + /// + public InvoiceListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => InvoiceListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Invoices/InvoiceListParams.cs b/src/Orb/Models/Invoices/InvoiceListParams.cs index 1df26485..fe23c1c8 100644 --- a/src/Orb/Models/Invoices/InvoiceListParams.cs +++ b/src/Orb/Models/Invoices/InvoiceListParams.cs @@ -1,62 +1,47 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using InvoiceListParamsProperties = Orb.Models.Invoices.InvoiceListParamsProperties; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Invoices; /// -/// This endpoint returns a list of all [`Invoice`](/core-concepts#invoice)s for -/// an account in a list format. +/// This endpoint returns a list of all [`Invoice`](/core-concepts#invoice)s for an +/// account in a list format. /// -/// The list of invoices is ordered starting from the most recently issued invoice -/// date. The response also includes [`pagination_metadata`](/api-reference/pagination), -/// which lets the caller retrieve the next page of results if they exist. +/// The list of invoices is ordered starting from the most recently issued +/// invoice date. The response also includes [`pagination_metadata`](/api-reference/pagination), +/// which lets the caller retrieve the next page of results if they exist. /// -/// By default, this only returns invoices that are `issued`, `paid`, or `synced`. +/// By default, this only returns invoices that are `issued`, `paid`, or `synced`. /// -/// When fetching any `draft` invoices, this returns the last-computed invoice values -/// for each draft invoice, which may not always be up-to-date since Orb regularly -/// refreshes invoices asynchronously. +/// When fetching any `draft` invoices, this returns the last-computed invoice +/// values for each draft invoice, which may not always be up-to-date since Orb regularly +/// refreshes invoices asynchronously. /// -public sealed record class InvoiceListParams : Orb::ParamsBase +public sealed record class InvoiceListParams : ParamsBase { public string? Amount { - get - { - if (!this.QueryProperties.TryGetValue("amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "amount"); } + init { JsonModel.Set(this._rawQueryData, "amount", value); } } public string? AmountGt { - get - { - if (!this.QueryProperties.TryGetValue("amount[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["amount[gt]"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "amount[gt]"); } + init { JsonModel.Set(this._rawQueryData, "amount[gt]", value); } } public string? AmountLt { - get - { - if (!this.QueryProperties.TryGetValue("amount[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["amount[lt]"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "amount[lt]"); } + init { JsonModel.Set(this._rawQueryData, "amount[lt]", value); } } /// @@ -65,227 +50,119 @@ public string? AmountLt /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } public string? CustomerID { - get - { - if (!this.QueryProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "customer_id"); } + init { JsonModel.Set(this._rawQueryData, "customer_id", value); } } - public InvoiceListParamsProperties::DateType? DateType + public ApiEnum? DateType { get { - if (!this.QueryProperties.TryGetValue("date_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawQueryData, + "date_type" ); } - set { this.QueryProperties["date_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "date_type", value); } } - public System::DateOnly? DueDate + public string? DueDate { - get - { - if (!this.QueryProperties.TryGetValue("due_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["due_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "due_date"); } + init { JsonModel.Set(this._rawQueryData, "due_date", value); } } /// /// Filters invoices by their due dates within a specific time range in the past. - /// Specify the range as a number followed by 'd' (days) or 'm' (months). For example, - /// '7d' filters invoices due in the last 7 days, and '2m' filters those due in - /// the last 2 months. + /// Specify the range as a number followed by 'd' (days) or 'm' (months). For + /// example, '7d' filters invoices due in the last 7 days, and '2m' filters those + /// due in the last 2 months. /// public string? DueDateWindow { - get - { - if (!this.QueryProperties.TryGetValue("due_date_window", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["due_date_window"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "due_date_window"); } + init { JsonModel.Set(this._rawQueryData, "due_date_window", value); } } - public System::DateOnly? DueDateGt + public string? DueDateGt { - get - { - if (!this.QueryProperties.TryGetValue("due_date[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["due_date[gt]"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "due_date[gt]"); } + init { JsonModel.Set(this._rawQueryData, "due_date[gt]", value); } } - public System::DateOnly? DueDateLt + public string? DueDateLt { - get - { - if (!this.QueryProperties.TryGetValue("due_date[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["due_date[lt]"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "due_date[lt]"); } + init { JsonModel.Set(this._rawQueryData, "due_date[lt]", value); } } public string? ExternalCustomerID { get { - if ( - !this.QueryProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawQueryData, "external_customer_id"); } + init { JsonModel.Set(this._rawQueryData, "external_customer_id", value); } } - public System::DateTime? InvoiceDateGt + public System::DateTimeOffset? InvoiceDateGt { get { - if ( - !this.QueryProperties.TryGetValue("invoice_date[gt]", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["invoice_date[gt]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "invoice_date[gt]" ); } + init { JsonModel.Set(this._rawQueryData, "invoice_date[gt]", value); } } - public System::DateTime? InvoiceDateGte + public System::DateTimeOffset? InvoiceDateGte { get { - if ( - !this.QueryProperties.TryGetValue( - "invoice_date[gte]", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["invoice_date[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "invoice_date[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "invoice_date[gte]", value); } } - public System::DateTime? InvoiceDateLt + public System::DateTimeOffset? InvoiceDateLt { get { - if ( - !this.QueryProperties.TryGetValue("invoice_date[lt]", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["invoice_date[lt]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "invoice_date[lt]" ); } + init { JsonModel.Set(this._rawQueryData, "invoice_date[lt]", value); } } - public System::DateTime? InvoiceDateLte + public System::DateTimeOffset? InvoiceDateLte { get { - if ( - !this.QueryProperties.TryGetValue( - "invoice_date[lte]", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["invoice_date[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "invoice_date[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "invoice_date[lte]", value); } } public bool? IsRecurring { - get - { - if (!this.QueryProperties.TryGetValue("is_recurring", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["is_recurring"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawQueryData, "is_recurring"); } + init { JsonModel.Set(this._rawQueryData, "is_recurring", value); } } /// @@ -293,61 +170,180 @@ public bool? IsRecurring /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public Generic::List? Status + public IReadOnlyList>? Status { get { - if (!this.QueryProperties.TryGetValue("status", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); + return JsonModel.GetNullableClass< + List> + >(this.RawQueryData, "status"); } - set { this.QueryProperties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "status", value); } } public string? SubscriptionID { - get - { - if (!this.QueryProperties.TryGetValue("subscription_id", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawQueryData, "subscription_id"); } + init { JsonModel.Set(this._rawQueryData, "subscription_id", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["subscription_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + public InvoiceListParams() { } + + public InvoiceListParams(InvoiceListParams invoiceListParams) + : base(invoiceListParams) { } + + public InvoiceListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; } +#pragma warning restore CS8618 - public override System::Uri Url(Orb::IOrbClient client) + /// + public static InvoiceListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/invoices") + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/invoices") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter(typeof(DateTypeConverter))] +public enum DateType +{ + DueDate, + InvoiceDate, +} + +sealed class DateTypeConverter : JsonConverter +{ + public override DateType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "due_date" => DateType.DueDate, + "invoice_date" => DateType.InvoiceDate, + _ => (DateType)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, DateType value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + DateType.DueDate => "due_date", + DateType.InvoiceDate => "invoice_date", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Invoices.StatusConverter))] +public enum Status +{ + Draft, + Issued, + Paid, + Synced, + Void, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.Invoices.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "draft" => global::Orb.Models.Invoices.Status.Draft, + "issued" => global::Orb.Models.Invoices.Status.Issued, + "paid" => global::Orb.Models.Invoices.Status.Paid, + "synced" => global::Orb.Models.Invoices.Status.Synced, + "void" => global::Orb.Models.Invoices.Status.Void, + _ => (global::Orb.Models.Invoices.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Invoices.Status value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Invoices.Status.Draft => "draft", + global::Orb.Models.Invoices.Status.Issued => "issued", + global::Orb.Models.Invoices.Status.Paid => "paid", + global::Orb.Models.Invoices.Status.Synced => "synced", + global::Orb.Models.Invoices.Status.Void => "void", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Invoices/InvoiceListParamsProperties/DateType.cs b/src/Orb/Models/Invoices/InvoiceListParamsProperties/DateType.cs deleted file mode 100644 index 8100e75b..00000000 --- a/src/Orb/Models/Invoices/InvoiceListParamsProperties/DateType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceListParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DateType(string value) : Orb::IEnum -{ - public static readonly DateType DueDate = new("due_date"); - - public static readonly DateType InvoiceDate = new("invoice_date"); - - readonly string _value = value; - - public enum Value - { - DueDate, - InvoiceDate, - } - - public Value Known() => - _value switch - { - "due_date" => Value.DueDate, - "invoice_date" => Value.InvoiceDate, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DateType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceListParamsProperties/Status.cs b/src/Orb/Models/Invoices/InvoiceListParamsProperties/Status.cs deleted file mode 100644 index 5639e972..00000000 --- a/src/Orb/Models/Invoices/InvoiceListParamsProperties/Status.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Invoices.InvoiceListParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Draft = new("draft"); - - public static readonly Status Issued = new("issued"); - - public static readonly Status Paid = new("paid"); - - public static readonly Status Synced = new("synced"); - - public static readonly Status Void = new("void"); - - readonly string _value = value; - - public enum Value - { - Draft, - Issued, - Paid, - Synced, - Void, - } - - public Value Known() => - _value switch - { - "draft" => Value.Draft, - "issued" => Value.Issued, - "paid" => Value.Paid, - "synced" => Value.Synced, - "void" => Value.Void, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Invoices/InvoiceMarkPaidParams.cs b/src/Orb/Models/Invoices/InvoiceMarkPaidParams.cs index 7e939afa..11a3077f 100644 --- a/src/Orb/Models/Invoices/InvoiceMarkPaidParams.cs +++ b/src/Orb/Models/Invoices/InvoiceMarkPaidParams.cs @@ -1,48 +1,35 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Invoices; /// -/// This endpoint allows an invoice's status to be set the `paid` status. This can -/// only be done to invoices that are in the `issued` status. +/// This endpoint allows an invoice's status to be set to the `paid` status. This +/// can only be done to invoices that are in the `issued` or `synced` status. /// -public sealed record class InvoiceMarkPaidParams : Orb::ParamsBase +public sealed record class InvoiceMarkPaidParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string InvoiceID; + public string? InvoiceID { get; init; } /// /// A date string to specify the date of the payment. /// - public required System::DateOnly PaymentReceivedDate + public required string PaymentReceivedDate { - get - { - if ( - !this.BodyProperties.TryGetValue( - "payment_received_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "payment_received_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["payment_received_date"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "payment_received_date"); } + init { JsonModel.Set(this._rawBodyData, "payment_received_date", value); } } /// @@ -50,14 +37,8 @@ public sealed record class InvoiceMarkPaidParams : Orb::ParamsBase /// public string? ExternalID { - get - { - if (!this.BodyProperties.TryGetValue("external_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["external_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_id"); } + init { JsonModel.Set(this._rawBodyData, "external_id", value); } } /// @@ -65,42 +46,83 @@ public string? ExternalID /// public string? Notes { - get - { - if (!this.BodyProperties.TryGetValue("notes", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "notes"); } + init { JsonModel.Set(this._rawBodyData, "notes", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["notes"] = Json::JsonSerializer.SerializeToElement(value); } + public InvoiceMarkPaidParams() { } + + public InvoiceMarkPaidParams(InvoiceMarkPaidParams invoiceMarkPaidParams) + : base(invoiceMarkPaidParams) + { + this._rawBodyData = [.. invoiceMarkPaidParams._rawBodyData]; + } + + public InvoiceMarkPaidParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceMarkPaidParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceMarkPaidParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}/mark_paid", this.InvoiceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Invoices/InvoicePayParams.cs b/src/Orb/Models/Invoices/InvoicePayParams.cs index 59feb9b4..12e36393 100644 --- a/src/Orb/Models/Invoices/InvoicePayParams.cs +++ b/src/Orb/Models/Invoices/InvoicePayParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Invoices; @@ -8,27 +12,65 @@ namespace Orb.Models.Invoices; /// This endpoint collects payment for an invoice using the customer's default payment /// method. This action can only be taken on invoices with status "issued". /// -public sealed record class InvoicePayParams : Orb::ParamsBase +public sealed record class InvoicePayParams : ParamsBase { - public required string InvoiceID; + public string? InvoiceID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public InvoicePayParams() { } + + public InvoicePayParams(InvoicePayParams invoicePayParams) + : base(invoicePayParams) { } + + public InvoicePayParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoicePayParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static InvoicePayParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}/pay", this.InvoiceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Invoices/InvoiceUpdateParams.cs b/src/Orb/Models/Invoices/InvoiceUpdateParams.cs index ce5bb160..3769c016 100644 --- a/src/Orb/Models/Invoices/InvoiceUpdateParams.cs +++ b/src/Orb/Models/Invoices/InvoiceUpdateParams.cs @@ -1,67 +1,617 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Invoices; /// -/// This endpoint allows you to update the `metadata` property on an invoice. If -/// you pass null for the metadata value, it will clear any existing metadata for -/// that invoice. +/// This endpoint allows you to update the `metadata`, `net_terms`, `due_date`, and +/// `invoice_date` properties on an invoice. If you pass null for the metadata value, +/// it will clear any existing metadata for that invoice. /// -/// `metadata` can be modified regardless of invoice state. +/// `metadata` can be modified regardless of invoice state. `net_terms`, `due_date`, +/// and `invoice_date` can only be modified if the invoice is in a `draft` state. +/// `invoice_date` can only be modified for non-subscription invoices. /// -public sealed record class InvoiceUpdateParams : Orb::ParamsBase +public sealed record class InvoiceUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } + + public string? InvoiceID { get; init; } - public required string InvoiceID; + /// + /// An optional custom due date for the invoice. If not set, the due date will + /// be calculated based on the `net_terms` value. + /// + public InvoiceUpdateParamsDueDate? DueDate + { + get + { + return JsonModel.GetNullableClass( + this.RawBodyData, + "due_date" + ); + } + init { JsonModel.Set(this._rawBodyData, "due_date", value); } + } + + /// + /// The date of the invoice. Can only be modified for one-off draft invoices. + /// + public InvoiceDate? InvoiceDate + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "invoice_date"); } + init { JsonModel.Set(this._rawBodyData, "invoice_date", value); } + } /// /// User-specified key/value pairs for the resource. Individual keys can be removed /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + /// + /// The net terms determines the due date of the invoice. Due date is calculated + /// based on the invoice or issuance date, depending on the account's configured + /// due date calculation method. A value of '0' here represents that the invoice + /// is due on issue, whereas a value of '30' represents that the customer has + /// 30 days to pay the invoice. Do not set this field if you want to set a custom + /// due date. + /// + public long? NetTerms + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "net_terms"); } + init { JsonModel.Set(this._rawBodyData, "net_terms", value); } + } + + public InvoiceUpdateParams() { } + + public InvoiceUpdateParams(InvoiceUpdateParams invoiceUpdateParams) + : base(invoiceUpdateParams) + { + this._rawBodyData = [.. invoiceUpdateParams._rawBodyData]; + } + + public InvoiceUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}", this.InvoiceID) + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}", this.InvoiceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +/// +/// An optional custom due date for the invoice. If not set, the due date will be +/// calculated based on the `net_terms` value. +/// +[JsonConverter(typeof(InvoiceUpdateParamsDueDateConverter))] +public record class InvoiceUpdateParamsDueDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public InvoiceUpdateParamsDueDate(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceUpdateParamsDueDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceUpdateParamsDueDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceUpdateParamsDueDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @date, + System::Func @dateTime + ) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + return this.Value switch { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceUpdateParamsDueDate" + ), + }; + } + + public static implicit operator InvoiceUpdateParamsDueDate(string value) => new(value); + + public static implicit operator InvoiceUpdateParamsDueDate(System::DateTimeOffset value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of InvoiceUpdateParamsDueDate" + ); } } + + public virtual bool Equals(InvoiceUpdateParamsDueDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class InvoiceUpdateParamsDueDateConverter : JsonConverter +{ + public override InvoiceUpdateParamsDueDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceUpdateParamsDueDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +/// +/// The date of the invoice. Can only be modified for one-off draft invoices. +/// +[JsonConverter(typeof(InvoiceDateConverter))] +public record class InvoiceDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public InvoiceDate(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public InvoiceDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDate(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDate([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @date, + System::Action @dateTime + ) + { + switch (this.Value) + { + case string value: + @date(value); + break; + case System::DateTimeOffset value: + @dateTime(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of InvoiceDate"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (System::DateTimeOffset value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @date, + System::Func @dateTime + ) + { + return this.Value switch + { + string value => @date(value), + System::DateTimeOffset value => @dateTime(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of InvoiceDate"), + }; + } + + public static implicit operator InvoiceDate(string value) => new(value); + + public static implicit operator InvoiceDate(System::DateTimeOffset value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of InvoiceDate"); + } + } + + public virtual bool Equals(InvoiceDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class InvoiceDateConverter : JsonConverter +{ + public override InvoiceDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + InvoiceDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } } diff --git a/src/Orb/Models/Invoices/InvoiceVoidParams.cs b/src/Orb/Models/Invoices/InvoiceVoidParams.cs index 4090942c..d71318f1 100644 --- a/src/Orb/Models/Invoices/InvoiceVoidParams.cs +++ b/src/Orb/Models/Invoices/InvoiceVoidParams.cs @@ -1,43 +1,85 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Invoices; /// -/// This endpoint allows an invoice's status to be set the `void` status. This can -/// only be done to invoices that are in the `issued` status. +/// This endpoint allows an invoice's status to be set to the `void` status. This +/// can only be done to invoices that are in the `issued` status. /// -/// If the associated invoice has used the customer balance to change the amount +/// If the associated invoice has used the customer balance to change the amount /// due, the customer balance operation will be reverted. For example, if the invoice /// used \$10 of customer balance, that amount will be added back to the customer -/// balance upon voiding. +/// balance upon voiding. /// -/// If the invoice was used to purchase a credit block, but the invoice is not yet -/// paid, the credit block will be voided. If the invoice was created due to a top-up, -/// the top-up will be disabled. +/// If the invoice was used to purchase a credit block, but the invoice is +/// not yet paid, the credit block will be voided. If the invoice was created due +/// to a top-up, the top-up will be disabled. /// -public sealed record class InvoiceVoidParams : Orb::ParamsBase +public sealed record class InvoiceVoidParams : ParamsBase { - public required string InvoiceID; + public string? InvoiceID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public InvoiceVoidParams() { } + + public InvoiceVoidParams(InvoiceVoidParams invoiceVoidParams) + : base(invoiceVoidParams) { } + + public InvoiceVoidParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + InvoiceVoidParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static InvoiceVoidParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/invoices/{0}/void", this.InvoiceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/ItemSlim.cs b/src/Orb/Models/ItemSlim.cs index 47f856fe..0e4c3e89 100644 --- a/src/Orb/Models/ItemSlim.cs +++ b/src/Orb/Models/ItemSlim.cs @@ -1,41 +1,37 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ItemSlim : Orb::ModelBase, Orb::IFromRaw +/// +/// A minimal representation of an Item containing only the essential identifying information. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ItemSlim : JsonModel { + /// + /// The Orb-assigned unique identifier for the item. + /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } + /// + /// The name of the item. + /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// public override void Validate() { _ = this.ID; @@ -44,18 +40,32 @@ public override void Validate() public ItemSlim() { } + public ItemSlim(ItemSlim itemSlim) + : base(itemSlim) { } + + public ItemSlim(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ItemSlim(Generic::Dictionary properties) + [SetsRequiredMembers] + ItemSlim(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static ItemSlim FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static ItemSlim FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class ItemSlimFromRaw : IFromRawJson +{ + /// + public ItemSlim FromRawUnchecked(IReadOnlyDictionary rawData) => + ItemSlim.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Items/Item.cs b/src/Orb/Models/Items/Item.cs index 11c3e4e3..a0572504 100644 --- a/src/Orb/Models/Items/Item.cs +++ b/src/Orb/Models/Items/Item.cs @@ -1,9 +1,10 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using ItemProperties = Orb.Models.Items.ItemProperties; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Items; @@ -13,57 +14,44 @@ namespace Orb.Models.Items; /// with all line items, billable metrics, and prices and are used for defining external /// sync behavior for invoices and tax calculation purposes. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Item : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Item : JsonModel { + /// + /// The Orb-assigned unique identifier for the item. + /// public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required System::DateTime CreatedAt + /// + /// The time at which the item was created. + /// + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } - public required Generic::List ExternalConnections + /// + /// A list of external connections for this item, used to sync with external invoicing + /// and tax systems. + /// + public required IReadOnlyList ExternalConnections { get { - if (!this.Properties.TryGetValue("external_connections", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_connections", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("external_connections"); - } - set - { - this.Properties["external_connections"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass>( + this.RawData, + "external_connections" ); } + init { JsonModel.Set(this._rawData, "external_connections", value); } } /// @@ -72,35 +60,37 @@ public required string ID /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// + /// The name of the item. + /// public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The time at which the item was archived. If null, the item is not archived. + /// + public System::DateTimeOffset? ArchivedAt { get { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); + return JsonModel.GetNullableStruct(this.RawData, "archived_at"); } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "archived_at", value); } } + /// public override void Validate() { _ = this.ID; @@ -109,25 +99,180 @@ public override void Validate() { item.Validate(); } - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.Name; + _ = this.ArchivedAt; } public Item() { } + public Item(Item item) + : base(item) { } + + public Item(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Item(Generic::Dictionary properties) + [SetsRequiredMembers] + Item(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Item FromRawUnchecked(Generic::Dictionary properties) + /// + public static Item FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ItemFromRaw : IFromRawJson +{ + /// + public Item FromRawUnchecked(IReadOnlyDictionary rawData) => + Item.FromRawUnchecked(rawData); +} + +/// +/// Represents a connection between an Item and an external system for invoicing +/// or tax calculation purposes. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ItemExternalConnection : JsonModel +{ + /// + /// The name of the external system this item is connected to. + /// + public required ApiEnum< + string, + ItemExternalConnectionExternalConnectionName + > ExternalConnectionName + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "external_connection_name"); + } + init { JsonModel.Set(this._rawData, "external_connection_name", value); } + } + + /// + /// The identifier of this item in the external system. + /// + public required string ExternalEntityID + { + get { return JsonModel.GetNotNullClass(this.RawData, "external_entity_id"); } + init { JsonModel.Set(this._rawData, "external_entity_id", value); } + } + + /// + public override void Validate() + { + this.ExternalConnectionName.Validate(); + _ = this.ExternalEntityID; + } + + public ItemExternalConnection() { } + + public ItemExternalConnection(ItemExternalConnection itemExternalConnection) + : base(itemExternalConnection) { } + + public ItemExternalConnection(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ItemExternalConnection(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ItemExternalConnection FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ItemExternalConnectionFromRaw : IFromRawJson +{ + /// + public ItemExternalConnection FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ItemExternalConnection.FromRawUnchecked(rawData); +} + +/// +/// The name of the external system this item is connected to. +/// +[JsonConverter(typeof(ItemExternalConnectionExternalConnectionNameConverter))] +public enum ItemExternalConnectionExternalConnectionName +{ + Stripe, + Quickbooks, + BillCom, + Netsuite, + Taxjar, + Avalara, + Anrok, + Numeral, +} + +sealed class ItemExternalConnectionExternalConnectionNameConverter + : JsonConverter +{ + public override ItemExternalConnectionExternalConnectionName Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => ItemExternalConnectionExternalConnectionName.Stripe, + "quickbooks" => ItemExternalConnectionExternalConnectionName.Quickbooks, + "bill.com" => ItemExternalConnectionExternalConnectionName.BillCom, + "netsuite" => ItemExternalConnectionExternalConnectionName.Netsuite, + "taxjar" => ItemExternalConnectionExternalConnectionName.Taxjar, + "avalara" => ItemExternalConnectionExternalConnectionName.Avalara, + "anrok" => ItemExternalConnectionExternalConnectionName.Anrok, + "numeral" => ItemExternalConnectionExternalConnectionName.Numeral, + _ => (ItemExternalConnectionExternalConnectionName)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ItemExternalConnectionExternalConnectionName value, + JsonSerializerOptions options + ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + ItemExternalConnectionExternalConnectionName.Stripe => "stripe", + ItemExternalConnectionExternalConnectionName.Quickbooks => "quickbooks", + ItemExternalConnectionExternalConnectionName.BillCom => "bill.com", + ItemExternalConnectionExternalConnectionName.Netsuite => "netsuite", + ItemExternalConnectionExternalConnectionName.Taxjar => "taxjar", + ItemExternalConnectionExternalConnectionName.Avalara => "avalara", + ItemExternalConnectionExternalConnectionName.Anrok => "anrok", + ItemExternalConnectionExternalConnectionName.Numeral => "numeral", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Items/ItemArchiveParams.cs b/src/Orb/Models/Items/ItemArchiveParams.cs index 3a0a7671..1aaca78e 100644 --- a/src/Orb/Models/Items/ItemArchiveParams.cs +++ b/src/Orb/Models/Items/ItemArchiveParams.cs @@ -1,33 +1,75 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Items; /// /// Archive item /// -public sealed record class ItemArchiveParams : Orb::ParamsBase +public sealed record class ItemArchiveParams : ParamsBase { - public required string ItemID; + public string? ItemID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public ItemArchiveParams() { } + + public ItemArchiveParams(ItemArchiveParams itemArchiveParams) + : base(itemArchiveParams) { } + + public ItemArchiveParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ItemArchiveParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ItemArchiveParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/items/{0}/archive", this.ItemID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Items/ItemCreateParams.cs b/src/Orb/Models/Items/ItemCreateParams.cs index 6ab77db2..b76c4a2b 100644 --- a/src/Orb/Models/Items/ItemCreateParams.cs +++ b/src/Orb/Models/Items/ItemCreateParams.cs @@ -1,33 +1,32 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Items; /// /// This endpoint is used to create an [Item](/core-concepts#item). /// -public sealed record class ItemCreateParams : Orb::ParamsBase +public sealed record class ItemCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// The name of the item. /// public required string Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } } /// @@ -35,41 +34,88 @@ public required string Name /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public ItemCreateParams() { } + + public ItemCreateParams(ItemCreateParams itemCreateParams) + : base(itemCreateParams) + { + this._rawBodyData = [.. itemCreateParams._rawBodyData]; + } + + public ItemCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ItemCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static ItemCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/items") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/items") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Items/ItemFetchParams.cs b/src/Orb/Models/Items/ItemFetchParams.cs index b606ff77..ec064530 100644 --- a/src/Orb/Models/Items/ItemFetchParams.cs +++ b/src/Orb/Models/Items/ItemFetchParams.cs @@ -1,32 +1,74 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Items; /// /// This endpoint returns an item identified by its item_id. /// -public sealed record class ItemFetchParams : Orb::ParamsBase +public sealed record class ItemFetchParams : ParamsBase { - public required string ItemID; + public string? ItemID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public ItemFetchParams() { } + + public ItemFetchParams(ItemFetchParams itemFetchParams) + : base(itemFetchParams) { } + + public ItemFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ItemFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ItemFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/items/{0}", this.ItemID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/items/{0}", this.ItemID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Items/ItemListPage.cs b/src/Orb/Models/Items/ItemListPage.cs new file mode 100644 index 00000000..d662555b --- /dev/null +++ b/src/Orb/Models/Items/ItemListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Items; + +public sealed class ItemListPage( + IItemService service, + ItemListParams parameters, + ItemListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Items/ItemListPageResponse.cs b/src/Orb/Models/Items/ItemListPageResponse.cs index c1825aaf..4525ba0f 100644 --- a/src/Orb/Models/Items/ItemListPageResponse.cs +++ b/src/Orb/Models/Items/ItemListPageResponse.cs @@ -1,50 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Items; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ItemListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ItemListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +40,35 @@ public override void Validate() public ItemListPageResponse() { } + public ItemListPageResponse(ItemListPageResponse itemListPageResponse) + : base(itemListPageResponse) { } + + public ItemListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ItemListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + ItemListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static ItemListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class ItemListPageResponseFromRaw : IFromRawJson +{ + /// + public ItemListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ItemListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Items/ItemListParams.cs b/src/Orb/Models/Items/ItemListParams.cs index 24037e62..b8a78d45 100644 --- a/src/Orb/Models/Items/ItemListParams.cs +++ b/src/Orb/Models/Items/ItemListParams.cs @@ -1,14 +1,17 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Items; /// /// This endpoint returns a list of all Items, ordered in descending order by creation time. /// -public sealed record class ItemListParams : Orb::ParamsBase +public sealed record class ItemListParams : ParamsBase { /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -16,14 +19,8 @@ public sealed record class ItemListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -31,30 +28,70 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public ItemListParams() { } + + public ItemListParams(ItemListParams itemListParams) + : base(itemListParams) { } + + public ItemListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ItemListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ItemListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/items") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/items") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Items/ItemProperties/ExternalConnection.cs b/src/Orb/Models/Items/ItemProperties/ExternalConnection.cs deleted file mode 100644 index 3102581a..00000000 --- a/src/Orb/Models/Items/ItemProperties/ExternalConnection.cs +++ /dev/null @@ -1,82 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using ExternalConnectionProperties = Orb.Models.Items.ItemProperties.ExternalConnectionProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Items.ItemProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ExternalConnection : Orb::ModelBase, Orb::IFromRaw -{ - public required ExternalConnectionProperties::ExternalConnectionName ExternalConnectionName - { - get - { - if ( - !this.Properties.TryGetValue( - "external_connection_name", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "external_connection_name", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("external_connection_name"); - } - set - { - this.Properties["external_connection_name"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required string ExternalEntityID - { - get - { - if (!this.Properties.TryGetValue("external_entity_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_entity_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("external_entity_id"); - } - set - { - this.Properties["external_entity_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.ExternalConnectionName.Validate(); - _ = this.ExternalEntityID; - } - - public ExternalConnection() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ExternalConnection(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ExternalConnection FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Items/ItemProperties/ExternalConnectionProperties/ExternalConnectionName.cs b/src/Orb/Models/Items/ItemProperties/ExternalConnectionProperties/ExternalConnectionName.cs deleted file mode 100644 index 876a7346..00000000 --- a/src/Orb/Models/Items/ItemProperties/ExternalConnectionProperties/ExternalConnectionName.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Items.ItemProperties.ExternalConnectionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExternalConnectionName(string value) - : Orb::IEnum -{ - public static readonly ExternalConnectionName Stripe = new("stripe"); - - public static readonly ExternalConnectionName Quickbooks = new("quickbooks"); - - public static readonly ExternalConnectionName BillCom = new("bill.com"); - - public static readonly ExternalConnectionName Netsuite = new("netsuite"); - - public static readonly ExternalConnectionName Taxjar = new("taxjar"); - - public static readonly ExternalConnectionName Avalara = new("avalara"); - - public static readonly ExternalConnectionName Anrok = new("anrok"); - - readonly string _value = value; - - public enum Value - { - Stripe, - Quickbooks, - BillCom, - Netsuite, - Taxjar, - Avalara, - Anrok, - } - - public Value Known() => - _value switch - { - "stripe" => Value.Stripe, - "quickbooks" => Value.Quickbooks, - "bill.com" => Value.BillCom, - "netsuite" => Value.Netsuite, - "taxjar" => Value.Taxjar, - "avalara" => Value.Avalara, - "anrok" => Value.Anrok, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExternalConnectionName FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Items/ItemUpdateParams.cs b/src/Orb/Models/Items/ItemUpdateParams.cs index f9c81690..94d39463 100644 --- a/src/Orb/Models/Items/ItemUpdateParams.cs +++ b/src/Orb/Models/Items/ItemUpdateParams.cs @@ -1,44 +1,39 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using ItemUpdateParamsProperties = Orb.Models.Items.ItemUpdateParamsProperties; -using Json = System.Text.Json; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Items; /// /// This endpoint can be used to update properties on the Item. /// -public sealed record class ItemUpdateParams : Orb::ParamsBase +public sealed record class ItemUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ItemID; + public string? ItemID { get; init; } - public Generic::List? ExternalConnections + public IReadOnlyList? ExternalConnections { get { - if ( - !this.BodyProperties.TryGetValue( - "external_connections", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["external_connections"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "external_connections" ); } + init { JsonModel.Set(this._rawBodyData, "external_connections", value); } } /// @@ -46,55 +41,233 @@ public sealed record class ItemUpdateParams : Orb::ParamsBase /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } public string? Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + public ItemUpdateParams() { } + + public ItemUpdateParams(ItemUpdateParams itemUpdateParams) + : base(itemUpdateParams) + { + this._rawBodyData = [.. itemUpdateParams._rawBodyData]; + } + + public ItemUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ItemUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; } +#pragma warning restore CS8618 - public override System::Uri Url(Orb::IOrbClient client) + /// + public static ItemUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/items/{0}", this.ItemID) + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/items/{0}", this.ItemID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +/// +/// Represents a connection between an Item and an external system for invoicing +/// or tax calculation purposes. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ExternalConnection : JsonModel +{ + /// + /// The name of the external system this item is connected to. + /// + public required ApiEnum ExternalConnectionName { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return JsonModel.GetNotNullClass>( + this.RawData, + "external_connection_name" + ); } + init { JsonModel.Set(this._rawData, "external_connection_name", value); } + } + + /// + /// The identifier of this item in the external system. + /// + public required string ExternalEntityID + { + get { return JsonModel.GetNotNullClass(this.RawData, "external_entity_id"); } + init { JsonModel.Set(this._rawData, "external_entity_id", value); } + } + + /// + public override void Validate() + { + this.ExternalConnectionName.Validate(); + _ = this.ExternalEntityID; + } + + public ExternalConnection() { } + + public ExternalConnection(ExternalConnection externalConnection) + : base(externalConnection) { } + + public ExternalConnection(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalConnection(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalConnection FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ExternalConnectionFromRaw : IFromRawJson +{ + /// + public ExternalConnection FromRawUnchecked(IReadOnlyDictionary rawData) => + ExternalConnection.FromRawUnchecked(rawData); +} + +/// +/// The name of the external system this item is connected to. +/// +[JsonConverter(typeof(ExternalConnectionNameConverter))] +public enum ExternalConnectionName +{ + Stripe, + Quickbooks, + BillCom, + Netsuite, + Taxjar, + Avalara, + Anrok, + Numeral, +} + +sealed class ExternalConnectionNameConverter : JsonConverter +{ + public override ExternalConnectionName Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "stripe" => ExternalConnectionName.Stripe, + "quickbooks" => ExternalConnectionName.Quickbooks, + "bill.com" => ExternalConnectionName.BillCom, + "netsuite" => ExternalConnectionName.Netsuite, + "taxjar" => ExternalConnectionName.Taxjar, + "avalara" => ExternalConnectionName.Avalara, + "anrok" => ExternalConnectionName.Anrok, + "numeral" => ExternalConnectionName.Numeral, + _ => (ExternalConnectionName)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExternalConnectionName value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ExternalConnectionName.Stripe => "stripe", + ExternalConnectionName.Quickbooks => "quickbooks", + ExternalConnectionName.BillCom => "bill.com", + ExternalConnectionName.Netsuite => "netsuite", + ExternalConnectionName.Taxjar => "taxjar", + ExternalConnectionName.Avalara => "avalara", + ExternalConnectionName.Anrok => "anrok", + ExternalConnectionName.Numeral => "numeral", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Items/ItemUpdateParamsProperties/ExternalConnection.cs b/src/Orb/Models/Items/ItemUpdateParamsProperties/ExternalConnection.cs deleted file mode 100644 index 9ad7af51..00000000 --- a/src/Orb/Models/Items/ItemUpdateParamsProperties/ExternalConnection.cs +++ /dev/null @@ -1,82 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using ExternalConnectionProperties = Orb.Models.Items.ItemUpdateParamsProperties.ExternalConnectionProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Items.ItemUpdateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ExternalConnection : Orb::ModelBase, Orb::IFromRaw -{ - public required ExternalConnectionProperties::ExternalConnectionName ExternalConnectionName - { - get - { - if ( - !this.Properties.TryGetValue( - "external_connection_name", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "external_connection_name", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("external_connection_name"); - } - set - { - this.Properties["external_connection_name"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required string ExternalEntityID - { - get - { - if (!this.Properties.TryGetValue("external_entity_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_entity_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("external_entity_id"); - } - set - { - this.Properties["external_entity_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.ExternalConnectionName.Validate(); - _ = this.ExternalEntityID; - } - - public ExternalConnection() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ExternalConnection(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ExternalConnection FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Items/ItemUpdateParamsProperties/ExternalConnectionProperties/ExternalConnectionName.cs b/src/Orb/Models/Items/ItemUpdateParamsProperties/ExternalConnectionProperties/ExternalConnectionName.cs deleted file mode 100644 index 6f76a491..00000000 --- a/src/Orb/Models/Items/ItemUpdateParamsProperties/ExternalConnectionProperties/ExternalConnectionName.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Items.ItemUpdateParamsProperties.ExternalConnectionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExternalConnectionName(string value) - : Orb::IEnum -{ - public static readonly ExternalConnectionName Stripe = new("stripe"); - - public static readonly ExternalConnectionName Quickbooks = new("quickbooks"); - - public static readonly ExternalConnectionName BillCom = new("bill.com"); - - public static readonly ExternalConnectionName Netsuite = new("netsuite"); - - public static readonly ExternalConnectionName Taxjar = new("taxjar"); - - public static readonly ExternalConnectionName Avalara = new("avalara"); - - public static readonly ExternalConnectionName Anrok = new("anrok"); - - readonly string _value = value; - - public enum Value - { - Stripe, - Quickbooks, - BillCom, - Netsuite, - Taxjar, - Avalara, - Anrok, - } - - public Value Known() => - _value switch - { - "stripe" => Value.Stripe, - "quickbooks" => Value.Quickbooks, - "bill.com" => Value.BillCom, - "netsuite" => Value.Netsuite, - "taxjar" => Value.Taxjar, - "avalara" => Value.Avalara, - "anrok" => Value.Anrok, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExternalConnectionName FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/MatrixConfig.cs b/src/Orb/Models/MatrixConfig.cs index e3d22ae3..a47aa928 100644 --- a/src/Orb/Models/MatrixConfig.cs +++ b/src/Orb/Models/MatrixConfig.cs @@ -1,82 +1,50 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MatrixConfig : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for matrix pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MatrixConfig : JsonModel { /// /// Default per unit rate for any usage not bucketed into a specified matrix_value /// public required string DefaultUnitAmount { - get - { - if (!this.Properties.TryGetValue("default_unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "default_unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("default_unit_amount"); - } - set - { - this.Properties["default_unit_amount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "default_unit_amount"); } + init { JsonModel.Set(this._rawData, "default_unit_amount", value); } } /// /// One or two event property values to evaluate matrix groups by /// - public required Generic::List Dimensions + public required IReadOnlyList Dimensions { - get - { - if (!this.Properties.TryGetValue("dimensions", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimensions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimensions"); - } - set { this.Properties["dimensions"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimensions"); } + init { JsonModel.Set(this._rawData, "dimensions", value); } } /// - /// Matrix values for specified matrix grouping keys + /// Matrix values configuration /// - public required Generic::List MatrixValues + public required IReadOnlyList MatrixValues { - get - { - if (!this.Properties.TryGetValue("matrix_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("matrix_values"); - } - set { this.Properties["matrix_values"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "matrix_values"); } + init { JsonModel.Set(this._rawData, "matrix_values", value); } } + /// public override void Validate() { _ = this.DefaultUnitAmount; - foreach (var item in this.Dimensions) - { - _ = item; - } + _ = this.Dimensions; foreach (var item in this.MatrixValues) { item.Validate(); @@ -85,18 +53,32 @@ public override void Validate() public MatrixConfig() { } + public MatrixConfig(MatrixConfig matrixConfig) + : base(matrixConfig) { } + + public MatrixConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MatrixConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + MatrixConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static MatrixConfig FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static MatrixConfig FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class MatrixConfigFromRaw : IFromRawJson +{ + /// + public MatrixConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + MatrixConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/MatrixSubLineItem.cs b/src/Orb/Models/MatrixSubLineItem.cs index c78a097d..9a3d46a8 100644 --- a/src/Orb/Models/MatrixSubLineItem.cs +++ b/src/Orb/Models/MatrixSubLineItem.cs @@ -1,107 +1,78 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MatrixSubLineItemProperties = Orb.Models.MatrixSubLineItemProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MatrixSubLineItem : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MatrixSubLineItem : JsonModel { /// /// The total amount for this sub line item. /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } public required SubLineItemGrouping? Grouping { - get - { - if (!this.Properties.TryGetValue("grouping", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["grouping"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } } public required SubLineItemMatrixConfig MatrixConfig { get { - if (!this.Properties.TryGetValue("matrix_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_config"); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_config" + ); } - set { this.Properties["matrix_config"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "matrix_config", value); } } public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } public required double Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } - public required MatrixSubLineItemProperties::Type Type + public required ApiEnum Type { get { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + /// The scaled quantity for this line item for specific pricing structures + /// + public double? ScaledQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "scaled_quantity"); } + init { JsonModel.Set(this._rawData, "scaled_quantity", value); } } + /// public override void Validate() { _ = this.Amount; @@ -110,22 +81,80 @@ public override void Validate() _ = this.Name; _ = this.Quantity; this.Type.Validate(); + _ = this.ScaledQuantity; } public MatrixSubLineItem() { } + public MatrixSubLineItem(MatrixSubLineItem matrixSubLineItem) + : base(matrixSubLineItem) { } + + public MatrixSubLineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MatrixSubLineItem(Generic::Dictionary properties) + [SetsRequiredMembers] + MatrixSubLineItem(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MatrixSubLineItem FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixSubLineItemFromRaw : IFromRawJson +{ + /// + public MatrixSubLineItem FromRawUnchecked(IReadOnlyDictionary rawData) => + MatrixSubLineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MatrixSubLineItemTypeConverter))] +public enum MatrixSubLineItemType +{ + Matrix, +} + +sealed class MatrixSubLineItemTypeConverter : JsonConverter +{ + public override MatrixSubLineItemType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix" => MatrixSubLineItemType.Matrix, + _ => (MatrixSubLineItemType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixSubLineItemType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MatrixSubLineItemType.Matrix => "matrix", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MatrixSubLineItemProperties/Type.cs b/src/Orb/Models/MatrixSubLineItemProperties/Type.cs deleted file mode 100644 index 11f011e4..00000000 --- a/src/Orb/Models/MatrixSubLineItemProperties/Type.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.MatrixSubLineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Matrix = new("matrix"); - - readonly string _value = value; - - public enum Value - { - Matrix, - } - - public Value Known() => - _value switch - { - "matrix" => Value.Matrix, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/MatrixValue.cs b/src/Orb/Models/MatrixValue.cs index c2e68a4d..421e6d1c 100644 --- a/src/Orb/Models/MatrixValue.cs +++ b/src/Orb/Models/MatrixValue.cs @@ -1,37 +1,25 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MatrixValue : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for a single matrix value +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MatrixValue : JsonModel { /// - /// One or two matrix keys to filter usage to this Matrix value by. For example, - /// ["region", "tier"] could be used to filter cloud usage by a cloud region and - /// an instance tier. + /// One or two matrix keys to filter usage to this Matrix value by /// - public required Generic::List DimensionValues + public required IReadOnlyList DimensionValues { - get - { - if (!this.Properties.TryGetValue("dimension_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimension_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimension_values"); - } - set - { - this.Properties["dimension_values"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimension_values"); } + init { JsonModel.Set(this._rawData, "dimension_values", value); } } /// @@ -39,43 +27,45 @@ public sealed record class MatrixValue : Orb::ModelBase, Orb::IFromRaw public required string UnitAmount { - get - { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); - } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } } + /// public override void Validate() { - foreach (var item in this.DimensionValues) - { - _ = item; - } + _ = this.DimensionValues; _ = this.UnitAmount; } public MatrixValue() { } + public MatrixValue(MatrixValue matrixValue) + : base(matrixValue) { } + + public MatrixValue(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MatrixValue(Generic::Dictionary properties) + [SetsRequiredMembers] + MatrixValue(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static MatrixValue FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static MatrixValue FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class MatrixValueFromRaw : IFromRawJson +{ + /// + public MatrixValue FromRawUnchecked(IReadOnlyDictionary rawData) => + MatrixValue.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/MatrixWithAllocationConfig.cs b/src/Orb/Models/MatrixWithAllocationConfig.cs index 7ac76c72..16976ed0 100644 --- a/src/Orb/Models/MatrixWithAllocationConfig.cs +++ b/src/Orb/Models/MatrixWithAllocationConfig.cs @@ -1,33 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MatrixWithAllocationConfig - : Orb::ModelBase, - Orb::IFromRaw +/// +/// Configuration for matrix pricing with usage allocation +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class MatrixWithAllocationConfig : JsonModel { /// - /// Allocation to be used to calculate the price + /// Usage allocation /// - public required double Allocation + public required string Allocation { - get - { - if (!this.Properties.TryGetValue("allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["allocation"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } } /// @@ -35,69 +29,40 @@ public required double Allocation /// public required string DefaultUnitAmount { - get - { - if (!this.Properties.TryGetValue("default_unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "default_unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("default_unit_amount"); - } - set - { - this.Properties["default_unit_amount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "default_unit_amount"); } + init { JsonModel.Set(this._rawData, "default_unit_amount", value); } } /// /// One or two event property values to evaluate matrix groups by /// - public required Generic::List Dimensions + public required IReadOnlyList Dimensions { - get - { - if (!this.Properties.TryGetValue("dimensions", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimensions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimensions"); - } - set { this.Properties["dimensions"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimensions"); } + init { JsonModel.Set(this._rawData, "dimensions", value); } } /// - /// Matrix values for specified matrix grouping keys + /// Matrix values configuration /// - public required Generic::List MatrixValues + public required IReadOnlyList MatrixValues { get { - if (!this.Properties.TryGetValue("matrix_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("matrix_values"); + return JsonModel.GetNotNullClass>( + this.RawData, + "matrix_values" + ); } - set { this.Properties["matrix_values"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "matrix_values", value); } } + /// public override void Validate() { _ = this.Allocation; _ = this.DefaultUnitAmount; - foreach (var item in this.Dimensions) - { - _ = item; - } + _ = this.Dimensions; foreach (var item in this.MatrixValues) { item.Validate(); @@ -106,18 +71,111 @@ public override void Validate() public MatrixWithAllocationConfig() { } + public MatrixWithAllocationConfig(MatrixWithAllocationConfig matrixWithAllocationConfig) + : base(matrixWithAllocationConfig) { } + + public MatrixWithAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MatrixWithAllocationConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + MatrixWithAllocationConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MatrixWithAllocationConfig FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithAllocationConfigFromRaw : IFromRawJson +{ + /// + public MatrixWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithAllocationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single matrix value +/// +[JsonConverter( + typeof(JsonModelConverter< + MatrixWithAllocationConfigMatrixValue, + MatrixWithAllocationConfigMatrixValueFromRaw + >) +)] +public sealed record class MatrixWithAllocationConfigMatrixValue : JsonModel +{ + /// + /// One or two matrix keys to filter usage to this Matrix value by. For example, + /// ["region", "tier"] could be used to filter cloud usage by a cloud region + /// and an instance tier. + /// + public required IReadOnlyList DimensionValues + { + get { return JsonModel.GetNotNullClass>(this.RawData, "dimension_values"); } + init { JsonModel.Set(this._rawData, "dimension_values", value); } } + + /// + /// Unit price for the specified dimension_values + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.DimensionValues; + _ = this.UnitAmount; + } + + public MatrixWithAllocationConfigMatrixValue() { } + + public MatrixWithAllocationConfigMatrixValue( + MatrixWithAllocationConfigMatrixValue matrixWithAllocationConfigMatrixValue + ) + : base(matrixWithAllocationConfigMatrixValue) { } + + public MatrixWithAllocationConfigMatrixValue(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithAllocationConfigMatrixValue(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithAllocationConfigMatrixValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithAllocationConfigMatrixValueFromRaw + : IFromRawJson +{ + /// + public MatrixWithAllocationConfigMatrixValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithAllocationConfigMatrixValue.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Maximum.cs b/src/Orb/Models/Maximum.cs index d2b2d971..033f2d5a 100644 --- a/src/Orb/Models/Maximum.cs +++ b/src/Orb/Models/Maximum.cs @@ -1,57 +1,38 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Maximum : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Maximum : JsonModel { /// - /// List of price_ids that this maximum amount applies to. For plan/plan phase maximums, - /// this can be a subset of prices. + /// List of price_ids that this maximum amount applies to. For plan/plan phase + /// maximums, this can be a subset of prices. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this maximum to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { - get - { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); - } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "filters"); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// @@ -59,26 +40,14 @@ public sealed record class Maximum : Orb::ModelBase, Orb::IFromRaw /// public required string MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("maximum_amount"); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } + /// public override void Validate() { - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -86,20 +55,223 @@ public override void Validate() _ = this.MaximumAmount; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public Maximum() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public Maximum(Maximum maximum) + : base(maximum) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public Maximum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + Maximum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Maximum FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaximumFromRaw : IFromRawJson +{ + /// + public Maximum FromRawUnchecked(IReadOnlyDictionary rawData) => + Maximum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MaximumFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MaximumFilter() { } + + public MaximumFilter(MaximumFilter maximumFilter) + : base(maximumFilter) { } + + public MaximumFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Maximum(Generic::Dictionary properties) + [SetsRequiredMembers] + MaximumFilter(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Maximum FromRawUnchecked( - Generic::Dictionary properties + /// + public static MaximumFilter FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaximumFilterFromRaw : IFromRawJson +{ + /// + public MaximumFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + MaximumFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MaximumFilterFieldConverter))] +public enum MaximumFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MaximumFilterFieldConverter : JsonConverter +{ + public override MaximumFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MaximumFilterField.PriceID, + "item_id" => MaximumFilterField.ItemID, + "price_type" => MaximumFilterField.PriceType, + "currency" => MaximumFilterField.Currency, + "pricing_unit_id" => MaximumFilterField.PricingUnitID, + _ => (MaximumFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaximumFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaximumFilterField.PriceID => "price_id", + MaximumFilterField.ItemID => "item_id", + MaximumFilterField.PriceType => "price_type", + MaximumFilterField.Currency => "currency", + MaximumFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MaximumFilterOperatorConverter))] +public enum MaximumFilterOperator +{ + Includes, + Excludes, +} + +sealed class MaximumFilterOperatorConverter : JsonConverter +{ + public override MaximumFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MaximumFilterOperator.Includes, + "excludes" => MaximumFilterOperator.Excludes, + _ => (MaximumFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaximumFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MaximumFilterOperator.Includes => "includes", + MaximumFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MaximumInterval.cs b/src/Orb/Models/MaximumInterval.cs index 4739866c..274a266c 100644 --- a/src/Orb/Models/MaximumInterval.cs +++ b/src/Orb/Models/MaximumInterval.cs @@ -1,78 +1,54 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MaximumInterval : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MaximumInterval : JsonModel { /// /// The price interval ids that this maximum interval applies to. /// - public required Generic::List AppliesToPriceIntervalIDs + public required IReadOnlyList AppliesToPriceIntervalIDs { get { - if ( - !this.Properties.TryGetValue( - "applies_to_price_interval_ids", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_interval_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_interval_ids"); - } - set - { - this.Properties["applies_to_price_interval_ids"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "applies_to_price_interval_ids" + ); } + init { JsonModel.Set(this._rawData, "applies_to_price_interval_ids", value); } } /// /// The end date of the maximum interval. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// /// The filters that determine which prices this maximum interval applies to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>(this.RawData, "filters"); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// @@ -81,44 +57,26 @@ public sealed record class MaximumInterval : Orb::ModelBase, Orb::IFromRaw public required string MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("maximum_amount"); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// /// The start date of the maximum interval. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { - foreach (var item in this.AppliesToPriceIntervalIDs) - { - _ = item; - } + _ = this.AppliesToPriceIntervalIDs; _ = this.EndDate; foreach (var item in this.Filters) { @@ -130,18 +88,220 @@ public override void Validate() public MaximumInterval() { } + public MaximumInterval(MaximumInterval maximumInterval) + : base(maximumInterval) { } + + public MaximumInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MaximumInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + MaximumInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static MaximumInterval FromRawUnchecked( - Generic::Dictionary properties + /// + public static MaximumInterval FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaximumIntervalFromRaw : IFromRawJson +{ + /// + public MaximumInterval FromRawUnchecked(IReadOnlyDictionary rawData) => + MaximumInterval.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MaximumIntervalFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MaximumIntervalFilter() { } + + public MaximumIntervalFilter(MaximumIntervalFilter maximumIntervalFilter) + : base(maximumIntervalFilter) { } + + public MaximumIntervalFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaximumIntervalFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaximumIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaximumIntervalFilterFromRaw : IFromRawJson +{ + /// + public MaximumIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaximumIntervalFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MaximumIntervalFilterFieldConverter))] +public enum MaximumIntervalFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MaximumIntervalFilterFieldConverter : JsonConverter +{ + public override MaximumIntervalFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MaximumIntervalFilterField.PriceID, + "item_id" => MaximumIntervalFilterField.ItemID, + "price_type" => MaximumIntervalFilterField.PriceType, + "currency" => MaximumIntervalFilterField.Currency, + "pricing_unit_id" => MaximumIntervalFilterField.PricingUnitID, + _ => (MaximumIntervalFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaximumIntervalFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaximumIntervalFilterField.PriceID => "price_id", + MaximumIntervalFilterField.ItemID => "item_id", + MaximumIntervalFilterField.PriceType => "price_type", + MaximumIntervalFilterField.Currency => "currency", + MaximumIntervalFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MaximumIntervalFilterOperatorConverter))] +public enum MaximumIntervalFilterOperator +{ + Includes, + Excludes, +} + +sealed class MaximumIntervalFilterOperatorConverter : JsonConverter +{ + public override MaximumIntervalFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MaximumIntervalFilterOperator.Includes, + "excludes" => MaximumIntervalFilterOperator.Excludes, + _ => (MaximumIntervalFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaximumIntervalFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MaximumIntervalFilterOperator.Includes => "includes", + MaximumIntervalFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Metrics/BillableMetric.cs b/src/Orb/Models/Metrics/BillableMetric.cs index b6070062..e3e26734 100644 --- a/src/Orb/Models/Metrics/BillableMetric.cs +++ b/src/Orb/Models/Metrics/BillableMetric.cs @@ -1,10 +1,11 @@ -using BillableMetricProperties = Orb.Models.Metrics.BillableMetricProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Items = Orb.Models.Items; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Items; using System = System; namespace Orb.Models.Metrics; @@ -14,35 +15,19 @@ namespace Orb.Models.Metrics; /// are defined by the query that transforms raw usage events into meaningful values /// for your customers. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BillableMetric : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BillableMetric : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } public required string? Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } /// @@ -50,17 +35,10 @@ public required string? Description /// with all line items, billable metrics, and prices and are used for defining /// external sync behavior for invoices and tax calculation purposes. /// - public required Items::Item Item + public required Item Item { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } } /// @@ -69,78 +47,119 @@ public required string? Description /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required BillableMetricProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } + /// public override void Validate() { _ = this.ID; _ = this.Description; this.Item.Validate(); - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; _ = this.Name; this.Status.Validate(); } public BillableMetric() { } + public BillableMetric(BillableMetric billableMetric) + : base(billableMetric) { } + + public BillableMetric(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BillableMetric(Generic::Dictionary properties) + [SetsRequiredMembers] + BillableMetric(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static BillableMetric FromRawUnchecked( - Generic::Dictionary properties + /// + public static BillableMetric FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BillableMetricFromRaw : IFromRawJson +{ + /// + public BillableMetric FromRawUnchecked(IReadOnlyDictionary rawData) => + BillableMetric.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Metrics.StatusConverter))] +public enum Status +{ + Active, + Draft, + Archived, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.Metrics.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => global::Orb.Models.Metrics.Status.Active, + "draft" => global::Orb.Models.Metrics.Status.Draft, + "archived" => global::Orb.Models.Metrics.Status.Archived, + _ => (global::Orb.Models.Metrics.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Metrics.Status value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Metrics.Status.Active => "active", + global::Orb.Models.Metrics.Status.Draft => "draft", + global::Orb.Models.Metrics.Status.Archived => "archived", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Metrics/BillableMetricProperties/Status.cs b/src/Orb/Models/Metrics/BillableMetricProperties/Status.cs deleted file mode 100644 index 6ef41337..00000000 --- a/src/Orb/Models/Metrics/BillableMetricProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Metrics.BillableMetricProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Draft = new("draft"); - - public static readonly Status Archived = new("archived"); - - readonly string _value = value; - - public enum Value - { - Active, - Draft, - Archived, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "draft" => Value.Draft, - "archived" => Value.Archived, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Metrics/MetricCreateParams.cs b/src/Orb/Models/Metrics/MetricCreateParams.cs index 421cfd85..e13de9f8 100644 --- a/src/Orb/Models/Metrics/MetricCreateParams.cs +++ b/src/Orb/Models/Metrics/MetricCreateParams.cs @@ -1,37 +1,34 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Metrics; /// /// This endpoint is used to create a [metric](/core-concepts###metric) using a SQL -/// string. See [SQL support](/extensibility/advanced-metrics#sql-support) for a -/// description of constructing SQL queries with examples. +/// string. See [SQL support](/extensibility/advanced-metrics#sql-support) for a description +/// of constructing SQL queries with examples. /// -public sealed record class MetricCreateParams : Orb::ParamsBase +public sealed record class MetricCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// A description of the metric. /// public required string? Description { - get - { - if (!this.BodyProperties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "description"); } + init { JsonModel.Set(this._rawBodyData, "description", value); } } /// @@ -39,18 +36,8 @@ public required string? Description /// public required string ItemID { - get - { - if (!this.BodyProperties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.BodyProperties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "item_id"); } + init { JsonModel.Set(this._rawBodyData, "item_id", value); } } /// @@ -58,15 +45,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } } /// @@ -74,15 +54,8 @@ public required string Name /// public required string Sql { - get - { - if (!this.BodyProperties.TryGetValue("sql", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("sql", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("sql"); - } - set { this.BodyProperties["sql"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "sql"); } + init { JsonModel.Set(this._rawBodyData, "sql", value); } } /// @@ -90,41 +63,88 @@ public required string Sql /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public MetricCreateParams() { } + + public MetricCreateParams(MetricCreateParams metricCreateParams) + : base(metricCreateParams) + { + this._rawBodyData = [.. metricCreateParams._rawBodyData]; + } + + public MetricCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MetricCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static MetricCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/metrics") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/metrics") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Metrics/MetricFetchParams.cs b/src/Orb/Models/Metrics/MetricFetchParams.cs index 007db620..89fc81aa 100644 --- a/src/Orb/Models/Metrics/MetricFetchParams.cs +++ b/src/Orb/Models/Metrics/MetricFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Metrics; @@ -8,26 +12,64 @@ namespace Orb.Models.Metrics; /// This endpoint is used to list [metrics](/core-concepts#metric). It returns information /// about the metrics including its name, description, and item. /// -public sealed record class MetricFetchParams : Orb::ParamsBase +public sealed record class MetricFetchParams : ParamsBase { - public required string MetricID; + public string? MetricID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public MetricFetchParams() { } + + public MetricFetchParams(MetricFetchParams metricFetchParams) + : base(metricFetchParams) { } + + public MetricFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MetricFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static MetricFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/metrics/{0}", this.MetricID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/metrics/{0}", this.MetricID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Metrics/MetricListPage.cs b/src/Orb/Models/Metrics/MetricListPage.cs new file mode 100644 index 00000000..8802afaa --- /dev/null +++ b/src/Orb/Models/Metrics/MetricListPage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Metrics; + +public sealed class MetricListPage( + IMetricService service, + MetricListParams parameters, + MetricListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Metrics/MetricListPageResponse.cs b/src/Orb/Models/Metrics/MetricListPageResponse.cs index 359d34f1..1fd39577 100644 --- a/src/Orb/Models/Metrics/MetricListPageResponse.cs +++ b/src/Orb/Models/Metrics/MetricListPageResponse.cs @@ -1,50 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Metrics; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MetricListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MetricListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +40,35 @@ public override void Validate() public MetricListPageResponse() { } + public MetricListPageResponse(MetricListPageResponse metricListPageResponse) + : base(metricListPageResponse) { } + + public MetricListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MetricListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + MetricListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MetricListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class MetricListPageResponseFromRaw : IFromRawJson +{ + /// + public MetricListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MetricListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Metrics/MetricListParams.cs b/src/Orb/Models/Metrics/MetricListParams.cs index 020ff2d5..0211ef86 100644 --- a/src/Orb/Models/Metrics/MetricListParams.cs +++ b/src/Orb/Models/Metrics/MetricListParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Metrics; @@ -10,70 +13,48 @@ namespace Orb.Models.Metrics; /// a metric identifier. It returns information about the metrics including its name, /// description, and item. /// -public sealed record class MetricListParams : Orb::ParamsBase +public sealed record class MetricListParams : ParamsBase { - public System::DateTime? CreatedAtGt + public DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[gt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "created_at[lt]"); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -82,14 +63,8 @@ public sealed record class MetricListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -97,30 +72,70 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public MetricListParams() { } + + public MetricListParams(MetricListParams metricListParams) + : base(metricListParams) { } + + public MetricListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MetricListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static MetricListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/metrics") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/metrics") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Metrics/MetricUpdateParams.cs b/src/Orb/Models/Metrics/MetricUpdateParams.cs index 1eb802fa..47309ffe 100644 --- a/src/Orb/Models/Metrics/MetricUpdateParams.cs +++ b/src/Orb/Models/Metrics/MetricUpdateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Metrics; @@ -11,54 +13,105 @@ namespace Orb.Models.Metrics; /// This endpoint allows you to update the `metadata` property on a metric. If you /// pass `null` for the metadata value, it will clear any existing metadata for that invoice. /// -public sealed record class MetricUpdateParams : Orb::ParamsBase +public sealed record class MetricUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string MetricID; + public string? MetricID { get; init; } /// /// User-specified key/value pairs for the resource. Individual keys can be removed /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public MetricUpdateParams() { } + + public MetricUpdateParams(MetricUpdateParams metricUpdateParams) + : base(metricUpdateParams) + { + this._rawBodyData = [.. metricUpdateParams._rawBodyData]; + } + + public MetricUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MetricUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static MetricUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/metrics/{0}", this.MetricID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/metrics/{0}", this.MetricID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Minimum.cs b/src/Orb/Models/Minimum.cs index b1b44cd2..55f53ab9 100644 --- a/src/Orb/Models/Minimum.cs +++ b/src/Orb/Models/Minimum.cs @@ -1,57 +1,38 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Minimum : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Minimum : JsonModel { /// - /// List of price_ids that this minimum amount applies to. For plan/plan phase minimums, - /// this can be a subset of prices. + /// List of price_ids that this minimum amount applies to. For plan/plan phase + /// minimums, this can be a subset of prices. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this minimum to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { - get - { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); - } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "filters"); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// @@ -59,26 +40,14 @@ public sealed record class Minimum : Orb::ModelBase, Orb::IFromRaw /// public required string MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("minimum_amount"); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } + /// public override void Validate() { - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -86,20 +55,223 @@ public override void Validate() _ = this.MinimumAmount; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public Minimum() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public Minimum(Minimum minimum) + : base(minimum) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public Minimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + Minimum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Minimum FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MinimumFromRaw : IFromRawJson +{ + /// + public Minimum FromRawUnchecked(IReadOnlyDictionary rawData) => + Minimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MinimumFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MinimumFilter() { } + + public MinimumFilter(MinimumFilter minimumFilter) + : base(minimumFilter) { } + + public MinimumFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Minimum(Generic::Dictionary properties) + [SetsRequiredMembers] + MinimumFilter(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Minimum FromRawUnchecked( - Generic::Dictionary properties + /// + public static MinimumFilter FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MinimumFilterFromRaw : IFromRawJson +{ + /// + public MinimumFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + MinimumFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MinimumFilterFieldConverter))] +public enum MinimumFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MinimumFilterFieldConverter : JsonConverter +{ + public override MinimumFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MinimumFilterField.PriceID, + "item_id" => MinimumFilterField.ItemID, + "price_type" => MinimumFilterField.PriceType, + "currency" => MinimumFilterField.Currency, + "pricing_unit_id" => MinimumFilterField.PricingUnitID, + _ => (MinimumFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MinimumFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MinimumFilterField.PriceID => "price_id", + MinimumFilterField.ItemID => "item_id", + MinimumFilterField.PriceType => "price_type", + MinimumFilterField.Currency => "currency", + MinimumFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MinimumFilterOperatorConverter))] +public enum MinimumFilterOperator +{ + Includes, + Excludes, +} + +sealed class MinimumFilterOperatorConverter : JsonConverter +{ + public override MinimumFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MinimumFilterOperator.Includes, + "excludes" => MinimumFilterOperator.Excludes, + _ => (MinimumFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MinimumFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MinimumFilterOperator.Includes => "includes", + MinimumFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MinimumInterval.cs b/src/Orb/Models/MinimumInterval.cs index b243698b..91402a18 100644 --- a/src/Orb/Models/MinimumInterval.cs +++ b/src/Orb/Models/MinimumInterval.cs @@ -1,78 +1,54 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MinimumInterval : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MinimumInterval : JsonModel { /// /// The price interval ids that this minimum interval applies to. /// - public required Generic::List AppliesToPriceIntervalIDs + public required IReadOnlyList AppliesToPriceIntervalIDs { get { - if ( - !this.Properties.TryGetValue( - "applies_to_price_interval_ids", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_interval_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_interval_ids"); - } - set - { - this.Properties["applies_to_price_interval_ids"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "applies_to_price_interval_ids" + ); } + init { JsonModel.Set(this._rawData, "applies_to_price_interval_ids", value); } } /// /// The end date of the minimum interval. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// /// The filters that determine which prices this minimum interval applies to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>(this.RawData, "filters"); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// @@ -81,44 +57,26 @@ public sealed record class MinimumInterval : Orb::ModelBase, Orb::IFromRaw public required string MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("minimum_amount"); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } /// /// The start date of the minimum interval. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { - foreach (var item in this.AppliesToPriceIntervalIDs) - { - _ = item; - } + _ = this.AppliesToPriceIntervalIDs; _ = this.EndDate; foreach (var item in this.Filters) { @@ -130,18 +88,220 @@ public override void Validate() public MinimumInterval() { } + public MinimumInterval(MinimumInterval minimumInterval) + : base(minimumInterval) { } + + public MinimumInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MinimumInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + MinimumInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static MinimumInterval FromRawUnchecked( - Generic::Dictionary properties + /// + public static MinimumInterval FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MinimumIntervalFromRaw : IFromRawJson +{ + /// + public MinimumInterval FromRawUnchecked(IReadOnlyDictionary rawData) => + MinimumInterval.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MinimumIntervalFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MinimumIntervalFilter() { } + + public MinimumIntervalFilter(MinimumIntervalFilter minimumIntervalFilter) + : base(minimumIntervalFilter) { } + + public MinimumIntervalFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MinimumIntervalFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MinimumIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MinimumIntervalFilterFromRaw : IFromRawJson +{ + /// + public MinimumIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MinimumIntervalFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MinimumIntervalFilterFieldConverter))] +public enum MinimumIntervalFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MinimumIntervalFilterFieldConverter : JsonConverter +{ + public override MinimumIntervalFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MinimumIntervalFilterField.PriceID, + "item_id" => MinimumIntervalFilterField.ItemID, + "price_type" => MinimumIntervalFilterField.PriceType, + "currency" => MinimumIntervalFilterField.Currency, + "pricing_unit_id" => MinimumIntervalFilterField.PricingUnitID, + _ => (MinimumIntervalFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MinimumIntervalFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MinimumIntervalFilterField.PriceID => "price_id", + MinimumIntervalFilterField.ItemID => "item_id", + MinimumIntervalFilterField.PriceType => "price_type", + MinimumIntervalFilterField.Currency => "currency", + MinimumIntervalFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MinimumIntervalFilterOperatorConverter))] +public enum MinimumIntervalFilterOperator +{ + Includes, + Excludes, +} + +sealed class MinimumIntervalFilterOperatorConverter : JsonConverter +{ + public override MinimumIntervalFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MinimumIntervalFilterOperator.Includes, + "excludes" => MinimumIntervalFilterOperator.Excludes, + _ => (MinimumIntervalFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MinimumIntervalFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MinimumIntervalFilterOperator.Includes => "includes", + MinimumIntervalFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MonetaryAmountDiscountAdjustment.cs b/src/Orb/Models/MonetaryAmountDiscountAdjustment.cs index cbac484a..a3c47b9b 100644 --- a/src/Orb/Models/MonetaryAmountDiscountAdjustment.cs +++ b/src/Orb/Models/MonetaryAmountDiscountAdjustment.cs @@ -1,46 +1,38 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MonetaryAmountDiscountAdjustmentProperties = Orb.Models.MonetaryAmountDiscountAdjustmentProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MonetaryAmountDiscountAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + MonetaryAmountDiscountAdjustment, + MonetaryAmountDiscountAdjustmentFromRaw + >) +)] +public sealed record class MonetaryAmountDiscountAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required MonetaryAmountDiscountAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_type" + ); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// @@ -48,103 +40,56 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// - /// The amount by which to discount the prices this adjustment applies to in a given - /// billing period. + /// The amount by which to discount the prices this adjustment applies to in a + /// given billing period. /// public required string AmountDiscount { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_discount"); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -152,58 +97,28 @@ public required bool IsInvoiceLevel /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); _ = this.Amount; _ = this.AmountDiscount; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -213,20 +128,280 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public MonetaryAmountDiscountAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryAmountDiscountAdjustment( + MonetaryAmountDiscountAdjustment monetaryAmountDiscountAdjustment + ) + : base(monetaryAmountDiscountAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryAmountDiscountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MonetaryAmountDiscountAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + MonetaryAmountDiscountAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MonetaryAmountDiscountAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryAmountDiscountAdjustmentFromRaw : IFromRawJson +{ + /// + public MonetaryAmountDiscountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryAmountDiscountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(AdjustmentTypeConverter))] +public enum AdjustmentType +{ + AmountDiscount, +} + +sealed class AdjustmentTypeConverter : JsonConverter +{ + public override AdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "amount_discount" => AdjustmentType.AmountDiscount, + _ => (AdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AdjustmentType.AmountDiscount => "amount_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MonetaryAmountDiscountAdjustmentFilter, + MonetaryAmountDiscountAdjustmentFilterFromRaw + >) +)] +public sealed record class MonetaryAmountDiscountAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MonetaryAmountDiscountAdjustmentFilter() { } + + public MonetaryAmountDiscountAdjustmentFilter( + MonetaryAmountDiscountAdjustmentFilter monetaryAmountDiscountAdjustmentFilter + ) + : base(monetaryAmountDiscountAdjustmentFilter) { } + + public MonetaryAmountDiscountAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MonetaryAmountDiscountAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MonetaryAmountDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryAmountDiscountAdjustmentFilterFromRaw + : IFromRawJson +{ + /// + public MonetaryAmountDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryAmountDiscountAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MonetaryAmountDiscountAdjustmentFilterFieldConverter))] +public enum MonetaryAmountDiscountAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MonetaryAmountDiscountAdjustmentFilterFieldConverter + : JsonConverter +{ + public override MonetaryAmountDiscountAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MonetaryAmountDiscountAdjustmentFilterField.PriceID, + "item_id" => MonetaryAmountDiscountAdjustmentFilterField.ItemID, + "price_type" => MonetaryAmountDiscountAdjustmentFilterField.PriceType, + "currency" => MonetaryAmountDiscountAdjustmentFilterField.Currency, + "pricing_unit_id" => MonetaryAmountDiscountAdjustmentFilterField.PricingUnitID, + _ => (MonetaryAmountDiscountAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryAmountDiscountAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryAmountDiscountAdjustmentFilterField.PriceID => "price_id", + MonetaryAmountDiscountAdjustmentFilterField.ItemID => "item_id", + MonetaryAmountDiscountAdjustmentFilterField.PriceType => "price_type", + MonetaryAmountDiscountAdjustmentFilterField.Currency => "currency", + MonetaryAmountDiscountAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MonetaryAmountDiscountAdjustmentFilterOperatorConverter))] +public enum MonetaryAmountDiscountAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class MonetaryAmountDiscountAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override MonetaryAmountDiscountAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MonetaryAmountDiscountAdjustmentFilterOperator.Includes, + "excludes" => MonetaryAmountDiscountAdjustmentFilterOperator.Excludes, + _ => (MonetaryAmountDiscountAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryAmountDiscountAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryAmountDiscountAdjustmentFilterOperator.Includes => "includes", + MonetaryAmountDiscountAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MonetaryAmountDiscountAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/MonetaryAmountDiscountAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index d4a7ae37..00000000 --- a/src/Orb/Models/MonetaryAmountDiscountAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.MonetaryAmountDiscountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType AmountDiscount = new("amount_discount"); - - readonly string _value = value; - - public enum Value - { - AmountDiscount, - } - - public Value Known() => - _value switch - { - "amount_discount" => Value.AmountDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/MonetaryMaximumAdjustment.cs b/src/Orb/Models/MonetaryMaximumAdjustment.cs index 89df5e0d..38c94df3 100644 --- a/src/Orb/Models/MonetaryMaximumAdjustment.cs +++ b/src/Orb/Models/MonetaryMaximumAdjustment.cs @@ -1,46 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MonetaryMaximumAdjustmentProperties = Orb.Models.MonetaryMaximumAdjustmentProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MonetaryMaximumAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class MonetaryMaximumAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required MonetaryMaximumAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// @@ -48,103 +36,56 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// - /// The maximum amount to charge in a given billing period for the prices this adjustment - /// applies to. + /// The maximum amount to charge in a given billing period for the prices this + /// adjustment applies to. /// public required string MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("maximum_amount"); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// @@ -152,57 +93,27 @@ public required string MaximumAmount /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); _ = this.Amount; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -213,20 +124,279 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public MonetaryMaximumAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryMaximumAdjustment(MonetaryMaximumAdjustment monetaryMaximumAdjustment) + : base(monetaryMaximumAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryMaximumAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MonetaryMaximumAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + MonetaryMaximumAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MonetaryMaximumAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryMaximumAdjustmentFromRaw : IFromRawJson +{ + /// + public MonetaryMaximumAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryMaximumAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MonetaryMaximumAdjustmentAdjustmentTypeConverter))] +public enum MonetaryMaximumAdjustmentAdjustmentType +{ + Maximum, +} + +sealed class MonetaryMaximumAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override MonetaryMaximumAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "maximum" => MonetaryMaximumAdjustmentAdjustmentType.Maximum, + _ => (MonetaryMaximumAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryMaximumAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryMaximumAdjustmentAdjustmentType.Maximum => "maximum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MonetaryMaximumAdjustmentFilter, + MonetaryMaximumAdjustmentFilterFromRaw + >) +)] +public sealed record class MonetaryMaximumAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MonetaryMaximumAdjustmentFilter() { } + + public MonetaryMaximumAdjustmentFilter( + MonetaryMaximumAdjustmentFilter monetaryMaximumAdjustmentFilter + ) + : base(monetaryMaximumAdjustmentFilter) { } + + public MonetaryMaximumAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MonetaryMaximumAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MonetaryMaximumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryMaximumAdjustmentFilterFromRaw : IFromRawJson +{ + /// + public MonetaryMaximumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryMaximumAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MonetaryMaximumAdjustmentFilterFieldConverter))] +public enum MonetaryMaximumAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MonetaryMaximumAdjustmentFilterFieldConverter + : JsonConverter +{ + public override MonetaryMaximumAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MonetaryMaximumAdjustmentFilterField.PriceID, + "item_id" => MonetaryMaximumAdjustmentFilterField.ItemID, + "price_type" => MonetaryMaximumAdjustmentFilterField.PriceType, + "currency" => MonetaryMaximumAdjustmentFilterField.Currency, + "pricing_unit_id" => MonetaryMaximumAdjustmentFilterField.PricingUnitID, + _ => (MonetaryMaximumAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryMaximumAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryMaximumAdjustmentFilterField.PriceID => "price_id", + MonetaryMaximumAdjustmentFilterField.ItemID => "item_id", + MonetaryMaximumAdjustmentFilterField.PriceType => "price_type", + MonetaryMaximumAdjustmentFilterField.Currency => "currency", + MonetaryMaximumAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MonetaryMaximumAdjustmentFilterOperatorConverter))] +public enum MonetaryMaximumAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class MonetaryMaximumAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override MonetaryMaximumAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MonetaryMaximumAdjustmentFilterOperator.Includes, + "excludes" => MonetaryMaximumAdjustmentFilterOperator.Excludes, + _ => (MonetaryMaximumAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryMaximumAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryMaximumAdjustmentFilterOperator.Includes => "includes", + MonetaryMaximumAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MonetaryMaximumAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/MonetaryMaximumAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 91e6bc20..00000000 --- a/src/Orb/Models/MonetaryMaximumAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.MonetaryMaximumAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType Maximum = new("maximum"); - - readonly string _value = value; - - public enum Value - { - Maximum, - } - - public Value Known() => - _value switch - { - "maximum" => Value.Maximum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/MonetaryMinimumAdjustment.cs b/src/Orb/Models/MonetaryMinimumAdjustment.cs index 53fe1944..7e8dc049 100644 --- a/src/Orb/Models/MonetaryMinimumAdjustment.cs +++ b/src/Orb/Models/MonetaryMinimumAdjustment.cs @@ -1,46 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MonetaryMinimumAdjustmentProperties = Orb.Models.MonetaryMinimumAdjustmentProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MonetaryMinimumAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class MonetaryMinimumAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required MonetaryMinimumAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// @@ -48,83 +36,46 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -132,38 +83,18 @@ public required bool IsInvoiceLevel /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } /// - /// The minimum amount to charge in a given billing period for the prices this adjustment - /// applies to. + /// The minimum amount to charge in a given billing period for the prices this + /// adjustment applies to. /// public required string MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("minimum_amount"); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } /// @@ -171,57 +102,27 @@ public required string MinimumAmount /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); _ = this.Amount; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -233,20 +134,279 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public MonetaryMinimumAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryMinimumAdjustment(MonetaryMinimumAdjustment monetaryMinimumAdjustment) + : base(monetaryMinimumAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryMinimumAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MonetaryMinimumAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + MonetaryMinimumAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MonetaryMinimumAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryMinimumAdjustmentFromRaw : IFromRawJson +{ + /// + public MonetaryMinimumAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryMinimumAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MonetaryMinimumAdjustmentAdjustmentTypeConverter))] +public enum MonetaryMinimumAdjustmentAdjustmentType +{ + Minimum, +} + +sealed class MonetaryMinimumAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override MonetaryMinimumAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "minimum" => MonetaryMinimumAdjustmentAdjustmentType.Minimum, + _ => (MonetaryMinimumAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryMinimumAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryMinimumAdjustmentAdjustmentType.Minimum => "minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MonetaryMinimumAdjustmentFilter, + MonetaryMinimumAdjustmentFilterFromRaw + >) +)] +public sealed record class MonetaryMinimumAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MonetaryMinimumAdjustmentFilter() { } + + public MonetaryMinimumAdjustmentFilter( + MonetaryMinimumAdjustmentFilter monetaryMinimumAdjustmentFilter + ) + : base(monetaryMinimumAdjustmentFilter) { } + + public MonetaryMinimumAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MonetaryMinimumAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MonetaryMinimumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryMinimumAdjustmentFilterFromRaw : IFromRawJson +{ + /// + public MonetaryMinimumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryMinimumAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MonetaryMinimumAdjustmentFilterFieldConverter))] +public enum MonetaryMinimumAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MonetaryMinimumAdjustmentFilterFieldConverter + : JsonConverter +{ + public override MonetaryMinimumAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MonetaryMinimumAdjustmentFilterField.PriceID, + "item_id" => MonetaryMinimumAdjustmentFilterField.ItemID, + "price_type" => MonetaryMinimumAdjustmentFilterField.PriceType, + "currency" => MonetaryMinimumAdjustmentFilterField.Currency, + "pricing_unit_id" => MonetaryMinimumAdjustmentFilterField.PricingUnitID, + _ => (MonetaryMinimumAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryMinimumAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryMinimumAdjustmentFilterField.PriceID => "price_id", + MonetaryMinimumAdjustmentFilterField.ItemID => "item_id", + MonetaryMinimumAdjustmentFilterField.PriceType => "price_type", + MonetaryMinimumAdjustmentFilterField.Currency => "currency", + MonetaryMinimumAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MonetaryMinimumAdjustmentFilterOperatorConverter))] +public enum MonetaryMinimumAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class MonetaryMinimumAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override MonetaryMinimumAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MonetaryMinimumAdjustmentFilterOperator.Includes, + "excludes" => MonetaryMinimumAdjustmentFilterOperator.Excludes, + _ => (MonetaryMinimumAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryMinimumAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryMinimumAdjustmentFilterOperator.Includes => "includes", + MonetaryMinimumAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MonetaryMinimumAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/MonetaryMinimumAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 33399b31..00000000 --- a/src/Orb/Models/MonetaryMinimumAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.MonetaryMinimumAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType Minimum = new("minimum"); - - readonly string _value = value; - - public enum Value - { - Minimum, - } - - public Value Known() => - _value switch - { - "minimum" => Value.Minimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/MonetaryPercentageDiscountAdjustment.cs b/src/Orb/Models/MonetaryPercentageDiscountAdjustment.cs index 6c762402..d755ab98 100644 --- a/src/Orb/Models/MonetaryPercentageDiscountAdjustment.cs +++ b/src/Orb/Models/MonetaryPercentageDiscountAdjustment.cs @@ -1,46 +1,40 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MonetaryPercentageDiscountAdjustmentProperties = Orb.Models.MonetaryPercentageDiscountAdjustmentProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MonetaryPercentageDiscountAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + MonetaryPercentageDiscountAdjustment, + MonetaryPercentageDiscountAdjustmentFromRaw + >) +)] +public sealed record class MonetaryPercentageDiscountAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required MonetaryPercentageDiscountAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum< + string, + MonetaryPercentageDiscountAdjustmentAdjustmentType + > AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// @@ -48,83 +42,46 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -133,20 +90,8 @@ public required bool IsInvoiceLevel /// public required double PercentageDiscount { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } } /// @@ -154,57 +99,27 @@ public required double PercentageDiscount /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); _ = this.Amount; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -215,20 +130,286 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public MonetaryPercentageDiscountAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryPercentageDiscountAdjustment( + MonetaryPercentageDiscountAdjustment monetaryPercentageDiscountAdjustment + ) + : base(monetaryPercentageDiscountAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryPercentageDiscountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MonetaryPercentageDiscountAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + MonetaryPercentageDiscountAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MonetaryPercentageDiscountAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryPercentageDiscountAdjustmentFromRaw + : IFromRawJson +{ + /// + public MonetaryPercentageDiscountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryPercentageDiscountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MonetaryPercentageDiscountAdjustmentAdjustmentTypeConverter))] +public enum MonetaryPercentageDiscountAdjustmentAdjustmentType +{ + PercentageDiscount, +} + +sealed class MonetaryPercentageDiscountAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override MonetaryPercentageDiscountAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage_discount" => + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + _ => (MonetaryPercentageDiscountAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryPercentageDiscountAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryPercentageDiscountAdjustmentAdjustmentType.PercentageDiscount => + "percentage_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MonetaryPercentageDiscountAdjustmentFilter, + MonetaryPercentageDiscountAdjustmentFilterFromRaw + >) +)] +public sealed record class MonetaryPercentageDiscountAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MonetaryPercentageDiscountAdjustmentFilter() { } + + public MonetaryPercentageDiscountAdjustmentFilter( + MonetaryPercentageDiscountAdjustmentFilter monetaryPercentageDiscountAdjustmentFilter + ) + : base(monetaryPercentageDiscountAdjustmentFilter) { } + + public MonetaryPercentageDiscountAdjustmentFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MonetaryPercentageDiscountAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MonetaryPercentageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryPercentageDiscountAdjustmentFilterFromRaw + : IFromRawJson +{ + /// + public MonetaryPercentageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryPercentageDiscountAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MonetaryPercentageDiscountAdjustmentFilterFieldConverter))] +public enum MonetaryPercentageDiscountAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MonetaryPercentageDiscountAdjustmentFilterFieldConverter + : JsonConverter +{ + public override MonetaryPercentageDiscountAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MonetaryPercentageDiscountAdjustmentFilterField.PriceID, + "item_id" => MonetaryPercentageDiscountAdjustmentFilterField.ItemID, + "price_type" => MonetaryPercentageDiscountAdjustmentFilterField.PriceType, + "currency" => MonetaryPercentageDiscountAdjustmentFilterField.Currency, + "pricing_unit_id" => MonetaryPercentageDiscountAdjustmentFilterField.PricingUnitID, + _ => (MonetaryPercentageDiscountAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryPercentageDiscountAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryPercentageDiscountAdjustmentFilterField.PriceID => "price_id", + MonetaryPercentageDiscountAdjustmentFilterField.ItemID => "item_id", + MonetaryPercentageDiscountAdjustmentFilterField.PriceType => "price_type", + MonetaryPercentageDiscountAdjustmentFilterField.Currency => "currency", + MonetaryPercentageDiscountAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MonetaryPercentageDiscountAdjustmentFilterOperatorConverter))] +public enum MonetaryPercentageDiscountAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class MonetaryPercentageDiscountAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override MonetaryPercentageDiscountAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MonetaryPercentageDiscountAdjustmentFilterOperator.Includes, + "excludes" => MonetaryPercentageDiscountAdjustmentFilterOperator.Excludes, + _ => (MonetaryPercentageDiscountAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryPercentageDiscountAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryPercentageDiscountAdjustmentFilterOperator.Includes => "includes", + MonetaryPercentageDiscountAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MonetaryPercentageDiscountAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/MonetaryPercentageDiscountAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index a78fc890..00000000 --- a/src/Orb/Models/MonetaryPercentageDiscountAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.MonetaryPercentageDiscountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType PercentageDiscount = new("percentage_discount"); - - readonly string _value = value; - - public enum Value - { - PercentageDiscount, - } - - public Value Known() => - _value switch - { - "percentage_discount" => Value.PercentageDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/MonetaryUsageDiscountAdjustment.cs b/src/Orb/Models/MonetaryUsageDiscountAdjustment.cs index 13d8cbf1..a2761629 100644 --- a/src/Orb/Models/MonetaryUsageDiscountAdjustment.cs +++ b/src/Orb/Models/MonetaryUsageDiscountAdjustment.cs @@ -1,46 +1,37 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MonetaryUsageDiscountAdjustmentProperties = Orb.Models.MonetaryUsageDiscountAdjustmentProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MonetaryUsageDiscountAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + MonetaryUsageDiscountAdjustment, + MonetaryUsageDiscountAdjustmentFromRaw + >) +)] +public sealed record class MonetaryUsageDiscountAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required MonetaryUsageDiscountAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// @@ -48,83 +39,46 @@ public required string ID /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -132,46 +86,18 @@ public required bool IsInvoiceLevel /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } /// @@ -180,28 +106,17 @@ public required string? ReplacesAdjustmentID /// public required double UsageDiscount { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); _ = this.Amount; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -212,20 +127,281 @@ public override void Validate() _ = this.UsageDiscount; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public MonetaryUsageDiscountAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryUsageDiscountAdjustment( + MonetaryUsageDiscountAdjustment monetaryUsageDiscountAdjustment + ) + : base(monetaryUsageDiscountAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public MonetaryUsageDiscountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MonetaryUsageDiscountAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + MonetaryUsageDiscountAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MonetaryUsageDiscountAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryUsageDiscountAdjustmentFromRaw : IFromRawJson +{ + /// + public MonetaryUsageDiscountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryUsageDiscountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MonetaryUsageDiscountAdjustmentAdjustmentTypeConverter))] +public enum MonetaryUsageDiscountAdjustmentAdjustmentType +{ + UsageDiscount, +} + +sealed class MonetaryUsageDiscountAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override MonetaryUsageDiscountAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_discount" => MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + _ => (MonetaryUsageDiscountAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryUsageDiscountAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryUsageDiscountAdjustmentAdjustmentType.UsageDiscount => "usage_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MonetaryUsageDiscountAdjustmentFilter, + MonetaryUsageDiscountAdjustmentFilterFromRaw + >) +)] +public sealed record class MonetaryUsageDiscountAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MonetaryUsageDiscountAdjustmentFilter() { } + + public MonetaryUsageDiscountAdjustmentFilter( + MonetaryUsageDiscountAdjustmentFilter monetaryUsageDiscountAdjustmentFilter + ) + : base(monetaryUsageDiscountAdjustmentFilter) { } + + public MonetaryUsageDiscountAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MonetaryUsageDiscountAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MonetaryUsageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MonetaryUsageDiscountAdjustmentFilterFromRaw + : IFromRawJson +{ + /// + public MonetaryUsageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MonetaryUsageDiscountAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MonetaryUsageDiscountAdjustmentFilterFieldConverter))] +public enum MonetaryUsageDiscountAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MonetaryUsageDiscountAdjustmentFilterFieldConverter + : JsonConverter +{ + public override MonetaryUsageDiscountAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MonetaryUsageDiscountAdjustmentFilterField.PriceID, + "item_id" => MonetaryUsageDiscountAdjustmentFilterField.ItemID, + "price_type" => MonetaryUsageDiscountAdjustmentFilterField.PriceType, + "currency" => MonetaryUsageDiscountAdjustmentFilterField.Currency, + "pricing_unit_id" => MonetaryUsageDiscountAdjustmentFilterField.PricingUnitID, + _ => (MonetaryUsageDiscountAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryUsageDiscountAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryUsageDiscountAdjustmentFilterField.PriceID => "price_id", + MonetaryUsageDiscountAdjustmentFilterField.ItemID => "item_id", + MonetaryUsageDiscountAdjustmentFilterField.PriceType => "price_type", + MonetaryUsageDiscountAdjustmentFilterField.Currency => "currency", + MonetaryUsageDiscountAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MonetaryUsageDiscountAdjustmentFilterOperatorConverter))] +public enum MonetaryUsageDiscountAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class MonetaryUsageDiscountAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override MonetaryUsageDiscountAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MonetaryUsageDiscountAdjustmentFilterOperator.Includes, + "excludes" => MonetaryUsageDiscountAdjustmentFilterOperator.Excludes, + _ => (MonetaryUsageDiscountAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MonetaryUsageDiscountAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + MonetaryUsageDiscountAdjustmentFilterOperator.Includes => "includes", + MonetaryUsageDiscountAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/MonetaryUsageDiscountAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/MonetaryUsageDiscountAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 2c06d25b..00000000 --- a/src/Orb/Models/MonetaryUsageDiscountAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.MonetaryUsageDiscountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType UsageDiscount = new("usage_discount"); - - readonly string _value = value; - - public enum Value - { - UsageDiscount, - } - - public Value Known() => - _value switch - { - "usage_discount" => Value.UsageDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewAllocationPrice.cs b/src/Orb/Models/NewAllocationPrice.cs index c5188cdc..be51aaf7 100644 --- a/src/Orb/Models/NewAllocationPrice.cs +++ b/src/Orb/Models/NewAllocationPrice.cs @@ -1,52 +1,33 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewAllocationPriceProperties = Orb.Models.NewAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewAllocationPrice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewAllocationPrice : JsonModel { /// /// An amount of the currency to allocate to the customer at the specified cadence. /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The cadence at which to allocate the amount to the customer. /// - public required NewAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "cadence"); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -55,18 +36,8 @@ public required string Amount /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -76,15 +47,9 @@ public CustomExpiration? CustomExpiration { get { - if (!this.Properties.TryGetValue("custom_expiration", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["custom_expiration"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawData, "custom_expiration"); } + init { JsonModel.Set(this._rawData, "custom_expiration", value); } } /// @@ -92,27 +57,57 @@ public CustomExpiration? CustomExpiration /// over to the next period. Set to null if using custom_expiration. /// public bool? ExpiresAtEndOfCadence + { + get { return JsonModel.GetNullableStruct(this.RawData, "expires_at_end_of_cadence"); } + init { JsonModel.Set(this._rawData, "expires_at_end_of_cadence", value); } + } + + /// + /// The filters that determine which items the allocation applies to. + /// + public IReadOnlyList? Filters { get { - if ( - !this.Properties.TryGetValue( - "expires_at_end_of_cadence", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawData, + "filters" + ); } - set + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// The item ID that line items representing charges for this allocation will + /// be associated with. If not provided, the default allocation item for the + /// currency will be used (e.g. 'Included Allocation (USD)'). + /// + public string? ItemID + { + get { return JsonModel.GetNullableClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The (per-unit) cost basis of each created block. If non-zero, a customer + /// will be invoiced according to the quantity and per unit cost basis specified + /// for the allocation each cadence. + /// + public string? PerUnitCostBasis + { + get { return JsonModel.GetNullableClass(this.RawData, "per_unit_cost_basis"); } + init { - this.Properties["expires_at_end_of_cadence"] = Json::JsonSerializer.SerializeToElement( - value - ); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "per_unit_cost_basis", value); } } + /// public override void Validate() { _ = this.Amount; @@ -120,22 +115,278 @@ public override void Validate() _ = this.Currency; this.CustomExpiration?.Validate(); _ = this.ExpiresAtEndOfCadence; + foreach (var item in this.Filters ?? []) + { + item.Validate(); + } + _ = this.ItemID; + _ = this.PerUnitCostBasis; } public NewAllocationPrice() { } + public NewAllocationPrice(NewAllocationPrice newAllocationPrice) + : base(newAllocationPrice) { } + + public NewAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewAllocationPriceFromRaw : IFromRawJson +{ + /// + public NewAllocationPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + NewAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence at which to allocate the amount to the customer. +/// +[JsonConverter(typeof(CadenceConverter))] +public enum Cadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, +} + +sealed class CadenceConverter : JsonConverter +{ + public override Cadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => Cadence.OneTime, + "monthly" => Cadence.Monthly, + "quarterly" => Cadence.Quarterly, + "semi_annual" => Cadence.SemiAnnual, + "annual" => Cadence.Annual, + _ => (Cadence)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Cadence value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Cadence.OneTime => "one_time", + Cadence.Monthly => "monthly", + Cadence.Quarterly => "quarterly", + Cadence.SemiAnnual => "semi_annual", + Cadence.Annual => "annual", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// A PriceFilter that only allows item_id field for block filters. +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewAllocationPriceFilter : JsonModel +{ + /// + /// The property of the price the block applies to. Only item_id is supported. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public NewAllocationPriceFilter() { } + + public NewAllocationPriceFilter(NewAllocationPriceFilter newAllocationPriceFilter) + : base(newAllocationPriceFilter) { } + + public NewAllocationPriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewAllocationPriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewAllocationPriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewAllocationPriceFilterFromRaw : IFromRawJson +{ + /// + public NewAllocationPriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewAllocationPriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price the block applies to. Only item_id is supported. +/// +[JsonConverter(typeof(NewAllocationPriceFilterFieldConverter))] +public enum NewAllocationPriceFilterField +{ + ItemID, +} + +sealed class NewAllocationPriceFilterFieldConverter : JsonConverter +{ + public override NewAllocationPriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "item_id" => NewAllocationPriceFilterField.ItemID, + _ => (NewAllocationPriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewAllocationPriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewAllocationPriceFilterField.ItemID => "item_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(NewAllocationPriceFilterOperatorConverter))] +public enum NewAllocationPriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class NewAllocationPriceFilterOperatorConverter + : JsonConverter +{ + public override NewAllocationPriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => NewAllocationPriceFilterOperator.Includes, + "excludes" => NewAllocationPriceFilterOperator.Excludes, + _ => (NewAllocationPriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewAllocationPriceFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewAllocationPriceFilterOperator.Includes => "includes", + NewAllocationPriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 9da997d4..00000000 --- a/src/Orb/Models/NewAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewAllocationPriceProperties; - -/// -/// The cadence at which to allocate the amount to the customer. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewAmountDiscount.cs b/src/Orb/Models/NewAmountDiscount.cs index 5aaa7c64..16135c04 100644 --- a/src/Orb/Models/NewAmountDiscount.cs +++ b/src/Orb/Models/NewAmountDiscount.cs @@ -1,102 +1,72 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewAmountDiscountProperties = Orb.Models.NewAmountDiscountProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewAmountDiscount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewAmountDiscount : JsonModel { - public required NewAmountDiscountProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_type" + ); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } public required string AmountDiscount { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_discount"); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } } /// /// If set, the adjustment will apply to every price on the subscription. /// - public NewAmountDiscountProperties::AppliesToAll? AppliesToAll + public ApiEnum? AppliesToAll { get { - if (!this.Properties.TryGetValue("applies_to_all", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_all" ); } - set { this.Properties["applies_to_all"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applies_to_all", value); } } /// /// The set of item IDs to which this adjustment applies. /// - public Generic::List? AppliesToItemIDs + public IReadOnlyList? AppliesToItemIDs { get { - if (!this.Properties.TryGetValue("applies_to_item_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_item_ids"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_item_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_item_ids", value); } } /// /// The set of price IDs to which this adjustment applies. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// @@ -104,80 +74,66 @@ public required string AmountDiscount /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// A list of filters that determine which prices this adjustment will apply to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// When false, this adjustment will be applied to a single price. Otherwise, it - /// will be applied at the invoice level, possibly to multiple prices. + /// When false, this adjustment will be applied to a single price. Otherwise, + /// it will be applied at the invoice level, possibly to multiple prices. /// public bool? IsInvoiceLevel { - get + get { return JsonModel.GetNullableStruct(this.RawData, "is_invoice_level"); } + init { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// /// If set, only prices of the specified type will have the adjustment applied. /// - public NewAmountDiscountProperties::PriceType? PriceType + public ApiEnum? PriceType { get { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "price_type" ); } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_type", value); } } + /// public override void Validate() { this.AdjustmentType.Validate(); _ = this.AmountDiscount; this.AppliesToAll?.Validate(); - foreach (var item in this.AppliesToItemIDs ?? []) - { - _ = item; - } - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToItemIDs; + _ = this.AppliesToPriceIDs; _ = this.Currency; foreach (var item in this.Filters ?? []) { @@ -189,18 +145,365 @@ public override void Validate() public NewAmountDiscount() { } + public NewAmountDiscount(NewAmountDiscount newAmountDiscount) + : base(newAmountDiscount) { } + + public NewAmountDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewAmountDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + NewAmountDiscount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewAmountDiscount FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewAmountDiscountFromRaw : IFromRawJson +{ + /// + public NewAmountDiscount FromRawUnchecked(IReadOnlyDictionary rawData) => + NewAmountDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewAmountDiscountAdjustmentTypeConverter))] +public enum NewAmountDiscountAdjustmentType +{ + AmountDiscount, +} + +sealed class NewAmountDiscountAdjustmentTypeConverter + : JsonConverter +{ + public override NewAmountDiscountAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "amount_discount" => NewAmountDiscountAdjustmentType.AmountDiscount, + _ => (NewAmountDiscountAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewAmountDiscountAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewAmountDiscountAdjustmentType.AmountDiscount => "amount_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, the adjustment will apply to every price on the subscription. +/// +[JsonConverter(typeof(AppliesToAllConverter))] +public enum AppliesToAll +{ + True, +} + +sealed class AppliesToAllConverter : JsonConverter +{ + public override AppliesToAll Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + true => AppliesToAll.True, + _ => (AppliesToAll)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AppliesToAll value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AppliesToAll.True => true, + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewAmountDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public NewAmountDiscountFilter() { } + + public NewAmountDiscountFilter(NewAmountDiscountFilter newAmountDiscountFilter) + : base(newAmountDiscountFilter) { } + + public NewAmountDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewAmountDiscountFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewAmountDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewAmountDiscountFilterFromRaw : IFromRawJson +{ + /// + public NewAmountDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewAmountDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(NewAmountDiscountFilterFieldConverter))] +public enum NewAmountDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class NewAmountDiscountFilterFieldConverter : JsonConverter +{ + public override NewAmountDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => NewAmountDiscountFilterField.PriceID, + "item_id" => NewAmountDiscountFilterField.ItemID, + "price_type" => NewAmountDiscountFilterField.PriceType, + "currency" => NewAmountDiscountFilterField.Currency, + "pricing_unit_id" => NewAmountDiscountFilterField.PricingUnitID, + _ => (NewAmountDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewAmountDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewAmountDiscountFilterField.PriceID => "price_id", + NewAmountDiscountFilterField.ItemID => "item_id", + NewAmountDiscountFilterField.PriceType => "price_type", + NewAmountDiscountFilterField.Currency => "currency", + NewAmountDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(NewAmountDiscountFilterOperatorConverter))] +public enum NewAmountDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class NewAmountDiscountFilterOperatorConverter + : JsonConverter +{ + public override NewAmountDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => NewAmountDiscountFilterOperator.Includes, + "excludes" => NewAmountDiscountFilterOperator.Excludes, + _ => (NewAmountDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewAmountDiscountFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewAmountDiscountFilterOperator.Includes => "includes", + NewAmountDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, only prices of the specified type will have the adjustment applied. +/// +[JsonConverter(typeof(PriceTypeConverter))] +public enum PriceType +{ + Usage, + FixedInAdvance, + FixedInArrears, + Fixed, + InArrears, +} + +sealed class PriceTypeConverter : JsonConverter +{ + public override PriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => PriceType.Usage, + "fixed_in_advance" => PriceType.FixedInAdvance, + "fixed_in_arrears" => PriceType.FixedInArrears, + "fixed" => PriceType.Fixed, + "in_arrears" => PriceType.InArrears, + _ => (PriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PriceType.Usage => "usage", + PriceType.FixedInAdvance => "fixed_in_advance", + PriceType.FixedInArrears => "fixed_in_arrears", + PriceType.Fixed => "fixed", + PriceType.InArrears => "in_arrears", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewAmountDiscountProperties/AdjustmentType.cs b/src/Orb/Models/NewAmountDiscountProperties/AdjustmentType.cs deleted file mode 100644 index aedca4c8..00000000 --- a/src/Orb/Models/NewAmountDiscountProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewAmountDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType AmountDiscount = new("amount_discount"); - - readonly string _value = value; - - public enum Value - { - AmountDiscount, - } - - public Value Known() => - _value switch - { - "amount_discount" => Value.AmountDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewAmountDiscountProperties/AppliesToAll.cs b/src/Orb/Models/NewAmountDiscountProperties/AppliesToAll.cs deleted file mode 100644 index 427370a4..00000000 --- a/src/Orb/Models/NewAmountDiscountProperties/AppliesToAll.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewAmountDiscountProperties; - -/// -/// If set, the adjustment will apply to every price on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AppliesToAll(bool value) : Orb::IEnum -{ - public static readonly AppliesToAll True = new(true); - - readonly bool _value = value; - - public enum Value - { - True, - } - - public Value Known() => - _value switch - { - true => Value.True, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public bool Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AppliesToAll FromRaw(bool value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewAmountDiscountProperties/PriceType.cs b/src/Orb/Models/NewAmountDiscountProperties/PriceType.cs deleted file mode 100644 index b042d86c..00000000 --- a/src/Orb/Models/NewAmountDiscountProperties/PriceType.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewAmountDiscountProperties; - -/// -/// If set, only prices of the specified type will have the adjustment applied. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType Usage = new("usage"); - - public static readonly PriceType FixedInAdvance = new("fixed_in_advance"); - - public static readonly PriceType FixedInArrears = new("fixed_in_arrears"); - - public static readonly PriceType Fixed = new("fixed"); - - public static readonly PriceType InArrears = new("in_arrears"); - - readonly string _value = value; - - public enum Value - { - Usage, - FixedInAdvance, - FixedInArrears, - Fixed, - InArrears, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - "fixed_in_advance" => Value.FixedInAdvance, - "fixed_in_arrears" => Value.FixedInArrears, - "fixed" => Value.Fixed, - "in_arrears" => Value.InArrears, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewBillingCycleConfiguration.cs b/src/Orb/Models/NewBillingCycleConfiguration.cs index 0696f624..59d89994 100644 --- a/src/Orb/Models/NewBillingCycleConfiguration.cs +++ b/src/Orb/Models/NewBillingCycleConfiguration.cs @@ -1,56 +1,43 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewBillingCycleConfigurationProperties = Orb.Models.NewBillingCycleConfigurationProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewBillingCycleConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewBillingCycleConfiguration : JsonModel { /// /// The duration of the billing period. /// public required long Duration { - get - { - if (!this.Properties.TryGetValue("duration", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "duration"); } + init { JsonModel.Set(this._rawData, "duration", value); } } /// /// The unit of billing period duration. /// - public required NewBillingCycleConfigurationProperties::DurationUnit DurationUnit + public required ApiEnum DurationUnit { get { - if (!this.Properties.TryGetValue("duration_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("duration_unit"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "duration_unit"); } - set { this.Properties["duration_unit"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "duration_unit", value); } } + /// public override void Validate() { _ = this.Duration; @@ -59,18 +46,83 @@ public override void Validate() public NewBillingCycleConfiguration() { } + public NewBillingCycleConfiguration(NewBillingCycleConfiguration newBillingCycleConfiguration) + : base(newBillingCycleConfiguration) { } + + public NewBillingCycleConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewBillingCycleConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewBillingCycleConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewBillingCycleConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewBillingCycleConfigurationFromRaw : IFromRawJson +{ + /// + public NewBillingCycleConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewBillingCycleConfiguration.FromRawUnchecked(rawData); +} + +/// +/// The unit of billing period duration. +/// +[JsonConverter(typeof(NewBillingCycleConfigurationDurationUnitConverter))] +public enum NewBillingCycleConfigurationDurationUnit +{ + Day, + Month, +} + +sealed class NewBillingCycleConfigurationDurationUnitConverter + : JsonConverter +{ + public override NewBillingCycleConfigurationDurationUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => NewBillingCycleConfigurationDurationUnit.Day, + "month" => NewBillingCycleConfigurationDurationUnit.Month, + _ => (NewBillingCycleConfigurationDurationUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewBillingCycleConfigurationDurationUnit value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewBillingCycleConfigurationDurationUnit.Day => "day", + NewBillingCycleConfigurationDurationUnit.Month => "month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewBillingCycleConfigurationProperties/DurationUnit.cs b/src/Orb/Models/NewBillingCycleConfigurationProperties/DurationUnit.cs deleted file mode 100644 index 4d1a37f5..00000000 --- a/src/Orb/Models/NewBillingCycleConfigurationProperties/DurationUnit.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewBillingCycleConfigurationProperties; - -/// -/// The unit of billing period duration. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DurationUnit(string value) : Orb::IEnum -{ - public static readonly DurationUnit Day = new("day"); - - public static readonly DurationUnit Month = new("month"); - - readonly string _value = value; - - public enum Value - { - Day, - Month, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - "month" => Value.Month, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DurationUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewDimensionalPriceConfiguration.cs b/src/Orb/Models/NewDimensionalPriceConfiguration.cs index 0701b67a..efff4921 100644 --- a/src/Orb/Models/NewDimensionalPriceConfiguration.cs +++ b/src/Orb/Models/NewDimensionalPriceConfiguration.cs @@ -1,37 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewDimensionalPriceConfiguration - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewDimensionalPriceConfiguration, + NewDimensionalPriceConfigurationFromRaw + >) +)] +public sealed record class NewDimensionalPriceConfiguration : JsonModel { /// /// The list of dimension values matching (in order) the dimensions of the price group /// - public required Generic::List DimensionValues + public required IReadOnlyList DimensionValues { - get - { - if (!this.Properties.TryGetValue("dimension_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimension_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimension_values"); - } - set - { - this.Properties["dimension_values"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimension_values"); } + init { JsonModel.Set(this._rawData, "dimension_values", value); } } /// @@ -41,22 +31,9 @@ public string? DimensionalPriceGroupID { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_group_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_group_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawData, "dimensional_price_group_id"); } + init { JsonModel.Set(this._rawData, "dimensional_price_group_id", value); } } /// @@ -66,47 +43,62 @@ public string? ExternalDimensionalPriceGroupID { get { - if ( - !this.Properties.TryGetValue( - "external_dimensional_price_group_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_dimensional_price_group_id"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "external_dimensional_price_group_id" + ); } + init { JsonModel.Set(this._rawData, "external_dimensional_price_group_id", value); } } + /// public override void Validate() { - foreach (var item in this.DimensionValues) - { - _ = item; - } + _ = this.DimensionValues; _ = this.DimensionalPriceGroupID; _ = this.ExternalDimensionalPriceGroupID; } public NewDimensionalPriceConfiguration() { } + public NewDimensionalPriceConfiguration( + NewDimensionalPriceConfiguration newDimensionalPriceConfiguration + ) + : base(newDimensionalPriceConfiguration) { } + + public NewDimensionalPriceConfiguration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewDimensionalPriceConfiguration(Generic::Dictionary properties) + [SetsRequiredMembers] + NewDimensionalPriceConfiguration(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewDimensionalPriceConfiguration FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public NewDimensionalPriceConfiguration(List dimensionValues) + : this() + { + this.DimensionValues = dimensionValues; + } +} + +class NewDimensionalPriceConfigurationFromRaw : IFromRawJson +{ + /// + public NewDimensionalPriceConfiguration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewDimensionalPriceConfiguration.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/NewFloatingBPSPrice.cs b/src/Orb/Models/NewFloatingBPSPrice.cs deleted file mode 100644 index 7dbaa67a..00000000 --- a/src/Orb/Models/NewFloatingBPSPrice.cs +++ /dev/null @@ -1,390 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingBPSPriceProperties = Orb.Models.NewFloatingBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingBPSPrice : Orb::ModelBase, Orb::IFromRaw -{ - public required BPSConfig BPSConfig - { - get - { - if (!this.Properties.TryGetValue("bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bps_config"); - } - set { this.Properties["bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The cadence to bill for this price on. - /// - public required NewFloatingBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 4217 currency string for which this price is billed in. - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewFloatingBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewFloatingBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.Currency; - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public NewFloatingBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewFloatingBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewFloatingBPSPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingBPSPriceProperties/Cadence.cs deleted file mode 100644 index b1805e96..00000000 --- a/src/Orb/Models/NewFloatingBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 50ce01aa..00000000 --- a/src/Orb/Models/NewFloatingBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index edd6c637..00000000 --- a/src/Orb/Models/NewFloatingBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingBPSPriceProperties = Orb.Models.NewFloatingBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingBPSPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingBPSPriceProperties/ModelType.cs deleted file mode 100644 index 33917b43..00000000 --- a/src/Orb/Models/NewFloatingBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BPS = new("bps"); - - readonly string _value = value; - - public enum Value - { - BPS, - } - - public Value Known() => - _value switch - { - "bps" => Value.BPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBulkBPSPrice.cs b/src/Orb/Models/NewFloatingBulkBPSPrice.cs deleted file mode 100644 index c2d3dddf..00000000 --- a/src/Orb/Models/NewFloatingBulkBPSPrice.cs +++ /dev/null @@ -1,393 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingBulkBPSPriceProperties = Orb.Models.NewFloatingBulkBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingBulkBPSPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - public required BulkBPSConfig BulkBPSConfig - { - get - { - if (!this.Properties.TryGetValue("bulk_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_bps_config"); - } - set { this.Properties["bulk_bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The cadence to bill for this price on. - /// - public required NewFloatingBulkBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 4217 currency string for which this price is billed in. - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewFloatingBulkBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewFloatingBulkBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BulkBPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.Currency; - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public NewFloatingBulkBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingBulkBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewFloatingBulkBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingBulkBPSPriceProperties/Cadence.cs deleted file mode 100644 index 2f1378b9..00000000 --- a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBulkBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index e90ccfdc..00000000 --- a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingBulkBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBulkBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index bbed0412..00000000 --- a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingBulkBPSPriceProperties = Orb.Models.NewFloatingBulkBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBulkBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingBulkBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingBulkBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ModelType.cs deleted file mode 100644 index db96a767..00000000 --- a/src/Orb/Models/NewFloatingBulkBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBulkBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkBPS = new("bulk_bps"); - - readonly string _value = value; - - public enum Value - { - BulkBPS, - } - - public Value Known() => - _value switch - { - "bulk_bps" => Value.BulkBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBulkPrice.cs b/src/Orb/Models/NewFloatingBulkPrice.cs index 257c5507..0767a889 100644 --- a/src/Orb/Models/NewFloatingBulkPrice.cs +++ b/src/Orb/Models/NewFloatingBulkPrice.cs @@ -1,52 +1,39 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingBulkPriceProperties = Orb.Models.NewFloatingBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingBulkPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewFloatingBulkPrice : JsonModel { + /// + /// Configuration for bulk pricing + /// public required BulkConfig BulkConfig { - get - { - if (!this.Properties.TryGetValue("bulk_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_config"); - } - set { this.Properties["bulk_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "bulk_config"); } + init { JsonModel.Set(this._rawData, "bulk_config", value); } } /// /// The cadence to bill for this price on. /// - public required NewFloatingBulkPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -54,18 +41,8 @@ public required BulkConfig BulkConfig /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -73,35 +50,23 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingBulkPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -109,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -125,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,41 +118,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingBulkPriceProperties::ConversionRateConfig? ConversionRateConfig + public ConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -230,21 +144,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +157,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +166,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,19 +175,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -313,21 +187,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,18 +200,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.BulkConfig.Validate(); @@ -365,29 +231,410 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingBulkPrice() { } + public NewFloatingBulkPrice(NewFloatingBulkPrice newFloatingBulkPrice) + : base(newFloatingBulkPrice) { } + + public NewFloatingBulkPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingBulkPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingBulkPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingBulkPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingBulkPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingBulkPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingBulkPriceCadenceConverter))] +public enum NewFloatingBulkPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingBulkPriceCadenceConverter : JsonConverter +{ + public override NewFloatingBulkPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingBulkPriceCadence.Annual, + "semi_annual" => NewFloatingBulkPriceCadence.SemiAnnual, + "monthly" => NewFloatingBulkPriceCadence.Monthly, + "quarterly" => NewFloatingBulkPriceCadence.Quarterly, + "one_time" => NewFloatingBulkPriceCadence.OneTime, + "custom" => NewFloatingBulkPriceCadence.Custom, + _ => (NewFloatingBulkPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingBulkPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingBulkPriceCadence.Annual => "annual", + NewFloatingBulkPriceCadence.SemiAnnual => "semi_annual", + NewFloatingBulkPriceCadence.Monthly => "monthly", + NewFloatingBulkPriceCadence.Quarterly => "quarterly", + NewFloatingBulkPriceCadence.OneTime => "one_time", + NewFloatingBulkPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(ModelTypeConverter))] +public enum ModelType +{ + Bulk, +} + +sealed class ModelTypeConverter : JsonConverter +{ + public override ModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "bulk" => ModelType.Bulk, + _ => (ModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ModelType.Bulk => "bulk", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ConversionRateConfigConverter))] +public record class ConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ConversionRateConfig(SharedUnitConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(SharedTieredConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ), + }; + } + + public static implicit operator ConversionRateConfig(SharedUnitConversionRateConfig value) => + new(value); + + public static implicit operator ConversionRateConfig(SharedTieredConversionRateConfig value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ConversionRateConfigConverter : JsonConverter +{ + public override ConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingBulkPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingBulkPriceProperties/Cadence.cs deleted file mode 100644 index d164cdde..00000000 --- a/src/Orb/Models/NewFloatingBulkPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBulkPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBulkPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingBulkPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index bc69f853..00000000 --- a/src/Orb/Models/NewFloatingBulkPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingBulkPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBulkPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingBulkPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingBulkPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 1767fc3b..00000000 --- a/src/Orb/Models/NewFloatingBulkPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingBulkPriceProperties = Orb.Models.NewFloatingBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBulkPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingBulkPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingBulkPriceProperties/ModelType.cs deleted file mode 100644 index fe35b777..00000000 --- a/src/Orb/Models/NewFloatingBulkPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBulkPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Bulk = new("bulk"); - - readonly string _value = value; - - public enum Value - { - Bulk, - } - - public Value Known() => - _value switch - { - "bulk" => Value.Bulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBulkWithProrationPrice.cs b/src/Orb/Models/NewFloatingBulkWithProrationPrice.cs index 97f6909c..8239f3f7 100644 --- a/src/Orb/Models/NewFloatingBulkWithProrationPrice.cs +++ b/src/Orb/Models/NewFloatingBulkWithProrationPrice.cs @@ -1,63 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingBulkWithProrationPriceProperties = Orb.Models.NewFloatingBulkWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingBulkWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingBulkWithProrationPrice, + NewFloatingBulkWithProrationPriceFromRaw + >) +)] +public sealed record class NewFloatingBulkWithProrationPrice : JsonModel { - public required Generic::Dictionary BulkWithProrationConfig + /// + /// Configuration for bulk_with_proration pricing + /// + public required BulkWithProrationConfig BulkWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "bulk_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "bulk_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("bulk_with_proration_config"); - } - set - { - this.Properties["bulk_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_proration_config" ); } + init { JsonModel.Set(this._rawData, "bulk_with_proration_config", value); } } /// /// The cadence to bill for this price on. /// - public required NewFloatingBulkWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -65,18 +51,8 @@ public sealed record class NewFloatingBulkWithProrationPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -84,35 +60,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingBulkWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -120,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -136,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -197,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingBulkWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingBulkWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -241,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -324,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,24 +209,22 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { - foreach (var item in this.BulkWithProrationConfig.Values) - { - _ = item; - } + this.BulkWithProrationConfig.Validate(); this.Cadence.Validate(); _ = this.Currency; _ = this.ItemID; @@ -379,29 +240,560 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingBulkWithProrationPrice() { } + public NewFloatingBulkWithProrationPrice( + NewFloatingBulkWithProrationPrice newFloatingBulkWithProrationPrice + ) + : base(newFloatingBulkWithProrationPrice) { } + + public NewFloatingBulkWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingBulkWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingBulkWithProrationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingBulkWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingBulkWithProrationPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingBulkWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingBulkWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_proration pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BulkWithProrationConfig : JsonModel +{ + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get { return JsonModel.GetNotNullClass>(this.RawData, "tiers"); } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithProrationConfig() { } + + public BulkWithProrationConfig(BulkWithProrationConfig bulkWithProrationConfig) + : base(bulkWithProrationConfig) { } + + public BulkWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BulkWithProrationConfig(List tiers) + : this() + { + this.Tiers = tiers; + } +} + +class BulkWithProrationConfigFromRaw : IFromRawJson +{ + /// + public BulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier with proration +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Tier : JsonModel +{ + /// + /// Cost per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public Tier() { } + + public Tier(Tier tier) + : base(tier) { } + + public Tier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Tier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Tier FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Tier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class TierFromRaw : IFromRawJson +{ + /// + public Tier FromRawUnchecked(IReadOnlyDictionary rawData) => + Tier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingBulkWithProrationPriceCadenceConverter))] +public enum NewFloatingBulkWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingBulkWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingBulkWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingBulkWithProrationPriceCadence.Annual, + "semi_annual" => NewFloatingBulkWithProrationPriceCadence.SemiAnnual, + "monthly" => NewFloatingBulkWithProrationPriceCadence.Monthly, + "quarterly" => NewFloatingBulkWithProrationPriceCadence.Quarterly, + "one_time" => NewFloatingBulkWithProrationPriceCadence.OneTime, + "custom" => NewFloatingBulkWithProrationPriceCadence.Custom, + _ => (NewFloatingBulkWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingBulkWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingBulkWithProrationPriceCadence.Annual => "annual", + NewFloatingBulkWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewFloatingBulkWithProrationPriceCadence.Monthly => "monthly", + NewFloatingBulkWithProrationPriceCadence.Quarterly => "quarterly", + NewFloatingBulkWithProrationPriceCadence.OneTime => "one_time", + NewFloatingBulkWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingBulkWithProrationPriceModelTypeConverter))] +public enum NewFloatingBulkWithProrationPriceModelType +{ + BulkWithProration, +} + +sealed class NewFloatingBulkWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingBulkWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "bulk_with_proration" => NewFloatingBulkWithProrationPriceModelType.BulkWithProration, + _ => (NewFloatingBulkWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingBulkWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingBulkWithProrationPriceModelType.BulkWithProration => + "bulk_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingBulkWithProrationPriceConversionRateConfigConverter))] +public record class NewFloatingBulkWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingBulkWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingBulkWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingBulkWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingBulkWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingBulkWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingBulkWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingBulkWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingBulkWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingBulkWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingBulkWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingBulkWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingBulkWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingBulkWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index ca77f526..00000000 --- a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBulkWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 29bb42ef..00000000 --- a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingBulkWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBulkWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 5c1ae0a9..00000000 --- a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingBulkWithProrationPriceProperties = Orb.Models.NewFloatingBulkWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingBulkWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingBulkWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingBulkWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index 6f641c05..00000000 --- a/src/Orb/Models/NewFloatingBulkWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingBulkWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkWithProration = new("bulk_with_proration"); - - readonly string _value = value; - - public enum Value - { - BulkWithProration, - } - - public Value Known() => - _value switch - { - "bulk_with_proration" => Value.BulkWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPrice.cs b/src/Orb/Models/NewFloatingCumulativeGroupedBulkPrice.cs index e8286a0c..e47ecd28 100644 --- a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPrice.cs +++ b/src/Orb/Models/NewFloatingCumulativeGroupedBulkPrice.cs @@ -1,62 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingCumulativeGroupedBulkPriceProperties = Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingCumulativeGroupedBulkPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingCumulativeGroupedBulkPrice, + NewFloatingCumulativeGroupedBulkPriceFromRaw + >) +)] +public sealed record class NewFloatingCumulativeGroupedBulkPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingCumulativeGroupedBulkPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary CumulativeGroupedBulkConfig + /// + /// Configuration for cumulative_grouped_bulk pricing + /// + public required CumulativeGroupedBulkConfig CumulativeGroupedBulkConfig { get { - if ( - !this.Properties.TryGetValue( - "cumulative_grouped_bulk_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "cumulative_grouped_bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("cumulative_grouped_bulk_config"); - } - set - { - this.Properties["cumulative_grouped_bulk_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_bulk_config" + ); } + init { JsonModel.Set(this._rawData, "cumulative_grouped_bulk_config", value); } } /// @@ -64,18 +51,8 @@ public sealed record class NewFloatingCumulativeGroupedBulkPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -83,35 +60,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingCumulativeGroupedBulkPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -119,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingCumulativeGroupedBulkPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingCumulativeGroupedBulkPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,25 +209,23 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.CumulativeGroupedBulkConfig.Values) - { - _ = item; - } + this.CumulativeGroupedBulkConfig.Validate(); _ = this.Currency; _ = this.ItemID; this.ModelType.Validate(); @@ -378,29 +240,576 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingCumulativeGroupedBulkPrice() { } + + public NewFloatingCumulativeGroupedBulkPrice( + NewFloatingCumulativeGroupedBulkPrice newFloatingCumulativeGroupedBulkPrice + ) + : base(newFloatingCumulativeGroupedBulkPrice) { } + + public NewFloatingCumulativeGroupedBulkPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingCumulativeGroupedBulkPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingCumulativeGroupedBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingCumulativeGroupedBulkPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingCumulativeGroupedBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingCumulativeGroupedBulkPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingCumulativeGroupedBulkPriceCadenceConverter))] +public enum NewFloatingCumulativeGroupedBulkPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingCumulativeGroupedBulkPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingCumulativeGroupedBulkPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingCumulativeGroupedBulkPriceCadence.Annual, + "semi_annual" => NewFloatingCumulativeGroupedBulkPriceCadence.SemiAnnual, + "monthly" => NewFloatingCumulativeGroupedBulkPriceCadence.Monthly, + "quarterly" => NewFloatingCumulativeGroupedBulkPriceCadence.Quarterly, + "one_time" => NewFloatingCumulativeGroupedBulkPriceCadence.OneTime, + "custom" => NewFloatingCumulativeGroupedBulkPriceCadence.Custom, + _ => (NewFloatingCumulativeGroupedBulkPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingCumulativeGroupedBulkPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingCumulativeGroupedBulkPriceCadence.Annual => "annual", + NewFloatingCumulativeGroupedBulkPriceCadence.SemiAnnual => "semi_annual", + NewFloatingCumulativeGroupedBulkPriceCadence.Monthly => "monthly", + NewFloatingCumulativeGroupedBulkPriceCadence.Quarterly => "quarterly", + NewFloatingCumulativeGroupedBulkPriceCadence.OneTime => "one_time", + NewFloatingCumulativeGroupedBulkPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_bulk pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CumulativeGroupedBulkConfig : JsonModel +{ + /// + /// Each tier lower bound must have the same group of values. + /// + public required IReadOnlyList DimensionValues + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "dimension_values" + ); } + init { JsonModel.Set(this._rawData, "dimension_values", value); } } - public NewFloatingCumulativeGroupedBulkPrice() { } + /// + /// Grouping key name + /// + public required string Group + { + get { return JsonModel.GetNotNullClass(this.RawData, "group"); } + init { JsonModel.Set(this._rawData, "group", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.DimensionValues) + { + item.Validate(); + } + _ = this.Group; + } + + public CumulativeGroupedBulkConfig() { } + + public CumulativeGroupedBulkConfig(CumulativeGroupedBulkConfig cumulativeGroupedBulkConfig) + : base(cumulativeGroupedBulkConfig) { } + + public CumulativeGroupedBulkConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingCumulativeGroupedBulkPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + CumulativeGroupedBulkConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingCumulativeGroupedBulkPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static CumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedBulkConfigFromRaw : IFromRawJson +{ + /// + public CumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedBulkConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a dimension value entry +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class DimensionValue : JsonModel +{ + /// + /// Grouping key value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Unit amount for this combination + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public DimensionValue() { } + + public DimensionValue(DimensionValue dimensionValue) + : base(dimensionValue) { } + + public DimensionValue(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionValue(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static DimensionValue FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DimensionValueFromRaw : IFromRawJson +{ + /// + public DimensionValue FromRawUnchecked(IReadOnlyDictionary rawData) => + DimensionValue.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingCumulativeGroupedBulkPriceModelTypeConverter))] +public enum NewFloatingCumulativeGroupedBulkPriceModelType +{ + CumulativeGroupedBulk, +} + +sealed class NewFloatingCumulativeGroupedBulkPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingCumulativeGroupedBulkPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "cumulative_grouped_bulk" => + NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + _ => (NewFloatingCumulativeGroupedBulkPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingCumulativeGroupedBulkPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk => + "cumulative_grouped_bulk", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingCumulativeGroupedBulkPriceConversionRateConfigConverter))] +public record class NewFloatingCumulativeGroupedBulkPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingCumulativeGroupedBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingCumulativeGroupedBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingCumulativeGroupedBulkPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingCumulativeGroupedBulkPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingCumulativeGroupedBulkPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingCumulativeGroupedBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingCumulativeGroupedBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingCumulativeGroupedBulkPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingCumulativeGroupedBulkPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingCumulativeGroupedBulkPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingCumulativeGroupedBulkPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingCumulativeGroupedBulkPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingCumulativeGroupedBulkPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/Cadence.cs deleted file mode 100644 index db47cb76..00000000 --- a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 831bc792..00000000 --- a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index a561e23c..00000000 --- a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingCumulativeGroupedBulkPriceProperties = Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingCumulativeGroupedBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingCumulativeGroupedBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ModelType.cs deleted file mode 100644 index de2a5ff8..00000000 --- a/src/Orb/Models/NewFloatingCumulativeGroupedBulkPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingCumulativeGroupedBulkPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType CumulativeGroupedBulk = new("cumulative_grouped_bulk"); - - readonly string _value = value; - - public enum Value - { - CumulativeGroupedBulk, - } - - public Value Known() => - _value switch - { - "cumulative_grouped_bulk" => Value.CumulativeGroupedBulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedAllocationPrice.cs b/src/Orb/Models/NewFloatingGroupedAllocationPrice.cs index 2436ead3..32bdfd44 100644 --- a/src/Orb/Models/NewFloatingGroupedAllocationPrice.cs +++ b/src/Orb/Models/NewFloatingGroupedAllocationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingGroupedAllocationPriceProperties = Orb.Models.NewFloatingGroupedAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingGroupedAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingGroupedAllocationPrice, + NewFloatingGroupedAllocationPriceFromRaw + >) +)] +public sealed record class NewFloatingGroupedAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingGroupedAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,45 +36,23 @@ public sealed record class NewFloatingGroupedAllocationPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Generic::Dictionary GroupedAllocationConfig + /// + /// Configuration for grouped_allocation pricing + /// + public required GroupedAllocationConfig GroupedAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_allocation_config"); - } - set - { - this.Properties["grouped_allocation_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_allocation_config" ); } + init { JsonModel.Set(this._rawData, "grouped_allocation_config", value); } } /// @@ -84,35 +60,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingGroupedAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -120,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -136,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -197,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingGroupedAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingGroupedAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -241,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -324,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,26 +209,24 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; - foreach (var item in this.GroupedAllocationConfig.Values) - { - _ = item; - } + this.GroupedAllocationConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -379,29 +240,500 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingGroupedAllocationPrice() { } + public NewFloatingGroupedAllocationPrice( + NewFloatingGroupedAllocationPrice newFloatingGroupedAllocationPrice + ) + : base(newFloatingGroupedAllocationPrice) { } + + public NewFloatingGroupedAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingGroupedAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingGroupedAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingGroupedAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingGroupedAllocationPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingGroupedAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingGroupedAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingGroupedAllocationPriceCadenceConverter))] +public enum NewFloatingGroupedAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingGroupedAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingGroupedAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingGroupedAllocationPriceCadence.Annual, + "semi_annual" => NewFloatingGroupedAllocationPriceCadence.SemiAnnual, + "monthly" => NewFloatingGroupedAllocationPriceCadence.Monthly, + "quarterly" => NewFloatingGroupedAllocationPriceCadence.Quarterly, + "one_time" => NewFloatingGroupedAllocationPriceCadence.OneTime, + "custom" => NewFloatingGroupedAllocationPriceCadence.Custom, + _ => (NewFloatingGroupedAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedAllocationPriceCadence.Annual => "annual", + NewFloatingGroupedAllocationPriceCadence.SemiAnnual => "semi_annual", + NewFloatingGroupedAllocationPriceCadence.Monthly => "monthly", + NewFloatingGroupedAllocationPriceCadence.Quarterly => "quarterly", + NewFloatingGroupedAllocationPriceCadence.OneTime => "one_time", + NewFloatingGroupedAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_allocation pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class GroupedAllocationConfig : JsonModel +{ + /// + /// Usage allocation per group + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// How to determine the groups that should each be allocated some quantity + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Unit rate for post-allocation + /// + public required string OverageUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "overage_unit_rate"); } + init { JsonModel.Set(this._rawData, "overage_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.GroupingKey; + _ = this.OverageUnitRate; + } + + public GroupedAllocationConfig() { } + + public GroupedAllocationConfig(GroupedAllocationConfig groupedAllocationConfig) + : base(groupedAllocationConfig) { } + + public GroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedAllocationConfigFromRaw : IFromRawJson +{ + /// + public GroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedAllocationConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingGroupedAllocationPriceModelTypeConverter))] +public enum NewFloatingGroupedAllocationPriceModelType +{ + GroupedAllocation, +} + +sealed class NewFloatingGroupedAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingGroupedAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_allocation" => NewFloatingGroupedAllocationPriceModelType.GroupedAllocation, + _ => (NewFloatingGroupedAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedAllocationPriceModelType.GroupedAllocation => + "grouped_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingGroupedAllocationPriceConversionRateConfigConverter))] +public record class NewFloatingGroupedAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingGroupedAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingGroupedAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingGroupedAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingGroupedAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingGroupedAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingGroupedAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingGroupedAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/Cadence.cs deleted file mode 100644 index c2b2e917..00000000 --- a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index be94e14d..00000000 --- a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingGroupedAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8b45c29d..00000000 --- a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingGroupedAllocationPriceProperties = Orb.Models.NewFloatingGroupedAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingGroupedAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingGroupedAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 4f3f876b..00000000 --- a/src/Orb/Models/NewFloatingGroupedAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedAllocation = new("grouped_allocation"); - - readonly string _value = value; - - public enum Value - { - GroupedAllocation, - } - - public Value Known() => - _value switch - { - "grouped_allocation" => Value.GroupedAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPackagePrice.cs b/src/Orb/Models/NewFloatingGroupedTieredPackagePrice.cs index fa3347e7..7b250584 100644 --- a/src/Orb/Models/NewFloatingGroupedTieredPackagePrice.cs +++ b/src/Orb/Models/NewFloatingGroupedTieredPackagePrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingGroupedTieredPackagePriceProperties = Orb.Models.NewFloatingGroupedTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingGroupedTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingGroupedTieredPackagePrice, + NewFloatingGroupedTieredPackagePriceFromRaw + >) +)] +public sealed record class NewFloatingGroupedTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingGroupedTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,44 +36,23 @@ public sealed record class NewFloatingGroupedTieredPackagePrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Generic::Dictionary GroupedTieredPackageConfig + /// + /// Configuration for grouped_tiered_package pricing + /// + public required GroupedTieredPackageConfig GroupedTieredPackageConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_package_config"); - } - set - { - this.Properties["grouped_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_package_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_tiered_package_config", value); } } /// @@ -83,35 +60,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingGroupedTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -119,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingGroupedTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingGroupedTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,26 +209,24 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; - foreach (var item in this.GroupedTieredPackageConfig.Values) - { - _ = item; - } + this.GroupedTieredPackageConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -378,29 +240,587 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingGroupedTieredPackagePrice() { } + + public NewFloatingGroupedTieredPackagePrice( + NewFloatingGroupedTieredPackagePrice newFloatingGroupedTieredPackagePrice + ) + : base(newFloatingGroupedTieredPackagePrice) { } + + public NewFloatingGroupedTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingGroupedTieredPackagePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingGroupedTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingGroupedTieredPackagePriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingGroupedTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingGroupedTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingGroupedTieredPackagePriceCadenceConverter))] +public enum NewFloatingGroupedTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingGroupedTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewFloatingGroupedTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingGroupedTieredPackagePriceCadence.Annual, + "semi_annual" => NewFloatingGroupedTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewFloatingGroupedTieredPackagePriceCadence.Monthly, + "quarterly" => NewFloatingGroupedTieredPackagePriceCadence.Quarterly, + "one_time" => NewFloatingGroupedTieredPackagePriceCadence.OneTime, + "custom" => NewFloatingGroupedTieredPackagePriceCadence.Custom, + _ => (NewFloatingGroupedTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingGroupedTieredPackagePriceCadence.Annual => "annual", + NewFloatingGroupedTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewFloatingGroupedTieredPackagePriceCadence.Monthly => "monthly", + NewFloatingGroupedTieredPackagePriceCadence.Quarterly => "quarterly", + NewFloatingGroupedTieredPackagePriceCadence.OneTime => "one_time", + NewFloatingGroupedTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class GroupedTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); } + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewFloatingGroupedTieredPackagePrice() { } + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public GroupedTieredPackageConfig() { } + + public GroupedTieredPackageConfig(GroupedTieredPackageConfig groupedTieredPackageConfig) + : base(groupedTieredPackageConfig) { } + + public GroupedTieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingGroupedTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + GroupedTieredPackageConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingGroupedTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static GroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageConfigFromRaw : IFromRawJson +{ + /// + public GroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredPackageConfigTier, + GroupedTieredPackageConfigTierFromRaw + >) +)] +public sealed record class GroupedTieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public GroupedTieredPackageConfigTier() { } + + public GroupedTieredPackageConfigTier( + GroupedTieredPackageConfigTier groupedTieredPackageConfigTier + ) + : base(groupedTieredPackageConfigTier) { } + + public GroupedTieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredPackageConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageConfigTierFromRaw : IFromRawJson +{ + /// + public GroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingGroupedTieredPackagePriceModelTypeConverter))] +public enum NewFloatingGroupedTieredPackagePriceModelType +{ + GroupedTieredPackage, +} + +sealed class NewFloatingGroupedTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingGroupedTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_tiered_package" => + NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage, + _ => (NewFloatingGroupedTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedTieredPackagePriceModelType.GroupedTieredPackage => + "grouped_tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingGroupedTieredPackagePriceConversionRateConfigConverter))] +public record class NewFloatingGroupedTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingGroupedTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingGroupedTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingGroupedTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingGroupedTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingGroupedTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingGroupedTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingGroupedTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index 7fbfeb24..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 311b7b37..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingGroupedTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f3fcb882..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingGroupedTieredPackagePriceProperties = Orb.Models.NewFloatingGroupedTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingGroupedTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingGroupedTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index 84dcf62d..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTieredPackage = new("grouped_tiered_package"); - - readonly string _value = value; - - public enum Value - { - GroupedTieredPackage, - } - - public Value Known() => - _value switch - { - "grouped_tiered_package" => Value.GroupedTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPrice.cs b/src/Orb/Models/NewFloatingGroupedTieredPrice.cs index 5c2071d8..594d1cdd 100644 --- a/src/Orb/Models/NewFloatingGroupedTieredPrice.cs +++ b/src/Orb/Models/NewFloatingGroupedTieredPrice.cs @@ -1,36 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingGroupedTieredPriceProperties = Orb.Models.NewFloatingGroupedTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingGroupedTieredPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewFloatingGroupedTieredPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingGroupedTieredPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,42 +34,23 @@ public sealed record class NewFloatingGroupedTieredPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Generic::Dictionary GroupedTieredConfig + /// + /// Configuration for grouped_tiered pricing + /// + public required GroupedTieredConfig GroupedTieredConfig { get { - if ( - !this.Properties.TryGetValue("grouped_tiered_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_config"); - } - set - { - this.Properties["grouped_tiered_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_config" ); } + init { JsonModel.Set(this._rawData, "grouped_tiered_config", value); } } /// @@ -81,35 +58,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingGroupedTieredPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -117,15 +81,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -133,60 +90,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -194,41 +125,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingGroupedTieredPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingGroupedTieredPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -238,21 +151,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +164,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +173,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +182,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +194,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,26 +207,24 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; - foreach (var item in this.GroupedTieredConfig.Values) - { - _ = item; - } + this.GroupedTieredConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -376,29 +238,560 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingGroupedTieredPrice() { } + + public NewFloatingGroupedTieredPrice( + NewFloatingGroupedTieredPrice newFloatingGroupedTieredPrice + ) + : base(newFloatingGroupedTieredPrice) { } + + public NewFloatingGroupedTieredPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingGroupedTieredPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingGroupedTieredPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingGroupedTieredPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingGroupedTieredPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingGroupedTieredPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingGroupedTieredPriceCadenceConverter))] +public enum NewFloatingGroupedTieredPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingGroupedTieredPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingGroupedTieredPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingGroupedTieredPriceCadence.Annual, + "semi_annual" => NewFloatingGroupedTieredPriceCadence.SemiAnnual, + "monthly" => NewFloatingGroupedTieredPriceCadence.Monthly, + "quarterly" => NewFloatingGroupedTieredPriceCadence.Quarterly, + "one_time" => NewFloatingGroupedTieredPriceCadence.OneTime, + "custom" => NewFloatingGroupedTieredPriceCadence.Custom, + _ => (NewFloatingGroupedTieredPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedTieredPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingGroupedTieredPriceCadence.Annual => "annual", + NewFloatingGroupedTieredPriceCadence.SemiAnnual => "semi_annual", + NewFloatingGroupedTieredPriceCadence.Monthly => "monthly", + NewFloatingGroupedTieredPriceCadence.Quarterly => "quarterly", + NewFloatingGroupedTieredPriceCadence.OneTime => "one_time", + NewFloatingGroupedTieredPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_tiered pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class GroupedTieredConfig : JsonModel +{ + /// + /// The billable metric property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Apply tiered pricing to each segment generated after grouping with the provided key + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "tiers"); } + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewFloatingGroupedTieredPrice() { } + /// + public override void Validate() + { + _ = this.GroupingKey; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public GroupedTieredConfig() { } + + public GroupedTieredConfig(GroupedTieredConfig groupedTieredConfig) + : base(groupedTieredConfig) { } + + public GroupedTieredConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingGroupedTieredPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + GroupedTieredConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingGroupedTieredPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static GroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredConfigFromRaw : IFromRawJson +{ + /// + public GroupedTieredConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + GroupedTieredConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class GroupedTieredConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public GroupedTieredConfigTier() { } + + public GroupedTieredConfigTier(GroupedTieredConfigTier groupedTieredConfigTier) + : base(groupedTieredConfigTier) { } + + public GroupedTieredConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredConfigTierFromRaw : IFromRawJson +{ + /// + public GroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingGroupedTieredPriceModelTypeConverter))] +public enum NewFloatingGroupedTieredPriceModelType +{ + GroupedTiered, +} + +sealed class NewFloatingGroupedTieredPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingGroupedTieredPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_tiered" => NewFloatingGroupedTieredPriceModelType.GroupedTiered, + _ => (NewFloatingGroupedTieredPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedTieredPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedTieredPriceModelType.GroupedTiered => "grouped_tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingGroupedTieredPriceConversionRateConfigConverter))] +public record class NewFloatingGroupedTieredPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingGroupedTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedTieredPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedTieredPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedTieredPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingGroupedTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingGroupedTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedTieredPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingGroupedTieredPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingGroupedTieredPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingGroupedTieredPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingGroupedTieredPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedTieredPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/Cadence.cs deleted file mode 100644 index 5cf5dd06..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedTieredPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index fb6fc01a..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingGroupedTieredPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedTieredPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index cb8d59fe..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingGroupedTieredPriceProperties = Orb.Models.NewFloatingGroupedTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedTieredPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingGroupedTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingGroupedTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ModelType.cs deleted file mode 100644 index 19cc4976..00000000 --- a/src/Orb/Models/NewFloatingGroupedTieredPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedTieredPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTiered = new("grouped_tiered"); - - readonly string _value = value; - - public enum Value - { - GroupedTiered, - } - - public Value Known() => - _value switch - { - "grouped_tiered" => Value.GroupedTiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPrice.cs b/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPrice.cs index 66bf8093..5e6122ff 100644 --- a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPrice.cs +++ b/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingGroupedWithMeteredMinimumPriceProperties = Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingGroupedWithMeteredMinimumPrice, + NewFloatingGroupedWithMeteredMinimumPriceFromRaw + >) )] -public sealed record class NewFloatingGroupedWithMeteredMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewFloatingGroupedWithMeteredMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingGroupedWithMeteredMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,44 +36,23 @@ public sealed record class NewFloatingGroupedWithMeteredMinimumPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Generic::Dictionary GroupedWithMeteredMinimumConfig + /// + /// Configuration for grouped_with_metered_minimum pricing + /// + public required GroupedWithMeteredMinimumConfig GroupedWithMeteredMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_with_metered_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_metered_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_with_metered_minimum_config"); - } - set - { - this.Properties["grouped_with_metered_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_metered_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_with_metered_minimum_config", value); } } /// @@ -85,35 +60,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingGroupedWithMeteredMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -121,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -137,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -198,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -242,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -325,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,26 +209,24 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; - foreach (var item in this.GroupedWithMeteredMinimumConfig.Values) - { - _ = item; - } + this.GroupedWithMeteredMinimumConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -380,31 +240,678 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingGroupedWithMeteredMinimumPrice() { } + + public NewFloatingGroupedWithMeteredMinimumPrice( + NewFloatingGroupedWithMeteredMinimumPrice newFloatingGroupedWithMeteredMinimumPrice + ) + : base(newFloatingGroupedWithMeteredMinimumPrice) { } + + public NewFloatingGroupedWithMeteredMinimumPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingGroupedWithMeteredMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingGroupedWithMeteredMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingGroupedWithMeteredMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingGroupedWithMeteredMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingGroupedWithMeteredMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingGroupedWithMeteredMinimumPriceCadenceConverter))] +public enum NewFloatingGroupedWithMeteredMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingGroupedWithMeteredMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingGroupedWithMeteredMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual, + "semi_annual" => NewFloatingGroupedWithMeteredMinimumPriceCadence.SemiAnnual, + "monthly" => NewFloatingGroupedWithMeteredMinimumPriceCadence.Monthly, + "quarterly" => NewFloatingGroupedWithMeteredMinimumPriceCadence.Quarterly, + "one_time" => NewFloatingGroupedWithMeteredMinimumPriceCadence.OneTime, + "custom" => NewFloatingGroupedWithMeteredMinimumPriceCadence.Custom, + _ => (NewFloatingGroupedWithMeteredMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedWithMeteredMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingGroupedWithMeteredMinimumPriceCadence.Annual => "annual", + NewFloatingGroupedWithMeteredMinimumPriceCadence.SemiAnnual => "semi_annual", + NewFloatingGroupedWithMeteredMinimumPriceCadence.Monthly => "monthly", + NewFloatingGroupedWithMeteredMinimumPriceCadence.Quarterly => "quarterly", + NewFloatingGroupedWithMeteredMinimumPriceCadence.OneTime => "one_time", + NewFloatingGroupedWithMeteredMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_metered_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMeteredMinimumConfig, + GroupedWithMeteredMinimumConfigFromRaw + >) +)] +public sealed record class GroupedWithMeteredMinimumConfig : JsonModel +{ + /// + /// Used to partition the usage into groups. The minimum amount is applied to + /// each group. + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group per unit + /// + public required string MinimumUnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_unit_amount"); } + init { JsonModel.Set(this._rawData, "minimum_unit_amount", value); } + } + + /// + /// Used to determine the unit rate + /// + public required string PricingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_key"); } + init { JsonModel.Set(this._rawData, "pricing_key", value); } + } + + /// + /// Scale the unit rates by the scaling factor. + /// + public required IReadOnlyList ScalingFactors + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "scaling_factors"); } + init { JsonModel.Set(this._rawData, "scaling_factors", value); } } - public NewFloatingGroupedWithMeteredMinimumPrice() { } + /// + /// Used to determine the unit rate scaling factor + /// + public required string ScalingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_key"); } + init { JsonModel.Set(this._rawData, "scaling_key", value); } + } + + /// + /// Apply per unit pricing to each pricing value. The minimum amount is applied + /// any unmatched usage. + /// + public required IReadOnlyList UnitAmounts + { + get { return JsonModel.GetNotNullClass>(this.RawData, "unit_amounts"); } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MinimumUnitAmount; + _ = this.PricingKey; + foreach (var item in this.ScalingFactors) + { + item.Validate(); + } + _ = this.ScalingKey; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public GroupedWithMeteredMinimumConfig() { } + + public GroupedWithMeteredMinimumConfig( + GroupedWithMeteredMinimumConfig groupedWithMeteredMinimumConfig + ) + : base(groupedWithMeteredMinimumConfig) { } + + public GroupedWithMeteredMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingGroupedWithMeteredMinimumPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + GroupedWithMeteredMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumConfigFromRaw : IFromRawJson +{ + /// + public GroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMeteredMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a scaling factor +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ScalingFactor : JsonModel +{ + /// + /// Scaling factor + /// + public required string ScalingFactorValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Scaling value + /// + public required string ScalingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_value"); } + init { JsonModel.Set(this._rawData, "scaling_value", value); } + } + + /// + public override void Validate() + { + _ = this.ScalingFactorValue; + _ = this.ScalingValue; + } + + public ScalingFactor() { } + + public ScalingFactor(ScalingFactor scalingFactor) + : base(scalingFactor) { } + + public ScalingFactor(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalingFactor(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingGroupedWithMeteredMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static ScalingFactor FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalingFactorFromRaw : IFromRawJson +{ + /// + public ScalingFactor FromRawUnchecked(IReadOnlyDictionary rawData) => + ScalingFactor.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a unit amount +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UnitAmount : JsonModel +{ + /// + /// Pricing value + /// + public required string PricingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_value"); } + init { JsonModel.Set(this._rawData, "pricing_value", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmountValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.PricingValue; + _ = this.UnitAmountValue; + } + + public UnitAmount() { } + + public UnitAmount(UnitAmount unitAmount) + : base(unitAmount) { } + + public UnitAmount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitAmount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitAmount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitAmountFromRaw : IFromRawJson +{ + /// + public UnitAmount FromRawUnchecked(IReadOnlyDictionary rawData) => + UnitAmount.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingGroupedWithMeteredMinimumPriceModelTypeConverter))] +public enum NewFloatingGroupedWithMeteredMinimumPriceModelType +{ + GroupedWithMeteredMinimum, +} + +sealed class NewFloatingGroupedWithMeteredMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingGroupedWithMeteredMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_with_metered_minimum" => + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + _ => (NewFloatingGroupedWithMeteredMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedWithMeteredMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum => + "grouped_with_metered_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfigConverter))] +public record class NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedWithMeteredMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/Cadence.cs deleted file mode 100644 index a1a5bbb1..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 47a97402..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 73c86492..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingGroupedWithMeteredMinimumPriceProperties = Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ModelType.cs deleted file mode 100644 index cd928323..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithMeteredMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedWithMeteredMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithMeteredMinimum = new( - "grouped_with_metered_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithMeteredMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_metered_minimum" => Value.GroupedWithMeteredMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPrice.cs b/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPrice.cs index 461612c8..6fd38a8e 100644 --- a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPrice.cs +++ b/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingGroupedWithProratedMinimumPriceProperties = Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingGroupedWithProratedMinimumPrice, + NewFloatingGroupedWithProratedMinimumPriceFromRaw + >) )] -public sealed record class NewFloatingGroupedWithProratedMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewFloatingGroupedWithProratedMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingGroupedWithProratedMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,45 +36,23 @@ public sealed record class NewFloatingGroupedWithProratedMinimumPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } - public required Generic::Dictionary GroupedWithProratedMinimumConfig + /// + /// Configuration for grouped_with_prorated_minimum pricing + /// + public required GroupedWithProratedMinimumConfig GroupedWithProratedMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_with_prorated_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_prorated_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException("grouped_with_prorated_minimum_config"); - } - set - { - this.Properties["grouped_with_prorated_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_prorated_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_with_prorated_minimum_config", value); } } /// @@ -86,35 +60,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingGroupedWithProratedMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -122,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -138,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -199,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingGroupedWithProratedMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -243,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -265,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -283,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -303,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -326,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -348,26 +209,24 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; - foreach (var item in this.GroupedWithProratedMinimumConfig.Values) - { - _ = item; - } + this.GroupedWithProratedMinimumConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -381,31 +240,513 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingGroupedWithProratedMinimumPrice() { } -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingGroupedWithProratedMinimumPrice( - Generic::Dictionary properties + public NewFloatingGroupedWithProratedMinimumPrice( + NewFloatingGroupedWithProratedMinimumPrice newFloatingGroupedWithProratedMinimumPrice + ) + : base(newFloatingGroupedWithProratedMinimumPrice) { } + + public NewFloatingGroupedWithProratedMinimumPrice( + IReadOnlyDictionary rawData ) { - Properties = properties; + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingGroupedWithProratedMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingGroupedWithProratedMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingGroupedWithProratedMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingGroupedWithProratedMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingGroupedWithProratedMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingGroupedWithProratedMinimumPriceCadenceConverter))] +public enum NewFloatingGroupedWithProratedMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingGroupedWithProratedMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingGroupedWithProratedMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingGroupedWithProratedMinimumPriceCadence.Annual, + "semi_annual" => NewFloatingGroupedWithProratedMinimumPriceCadence.SemiAnnual, + "monthly" => NewFloatingGroupedWithProratedMinimumPriceCadence.Monthly, + "quarterly" => NewFloatingGroupedWithProratedMinimumPriceCadence.Quarterly, + "one_time" => NewFloatingGroupedWithProratedMinimumPriceCadence.OneTime, + "custom" => NewFloatingGroupedWithProratedMinimumPriceCadence.Custom, + _ => (NewFloatingGroupedWithProratedMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedWithProratedMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedWithProratedMinimumPriceCadence.Annual => "annual", + NewFloatingGroupedWithProratedMinimumPriceCadence.SemiAnnual => "semi_annual", + NewFloatingGroupedWithProratedMinimumPriceCadence.Monthly => "monthly", + NewFloatingGroupedWithProratedMinimumPriceCadence.Quarterly => "quarterly", + NewFloatingGroupedWithProratedMinimumPriceCadence.OneTime => "one_time", + NewFloatingGroupedWithProratedMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_prorated_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithProratedMinimumConfig, + GroupedWithProratedMinimumConfigFromRaw + >) +)] +public sealed record class GroupedWithProratedMinimumConfig : JsonModel +{ + /// + /// How to determine the groups that should each have a minimum + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group + /// + public required string Minimum + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + /// + /// The amount to charge per unit + /// + public required string UnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rate"); } + init { JsonModel.Set(this._rawData, "unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.Minimum; + _ = this.UnitRate; + } + + public GroupedWithProratedMinimumConfig() { } + + public GroupedWithProratedMinimumConfig( + GroupedWithProratedMinimumConfig groupedWithProratedMinimumConfig + ) + : base(groupedWithProratedMinimumConfig) { } + + public GroupedWithProratedMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithProratedMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithProratedMinimumConfigFromRaw : IFromRawJson +{ + /// + public GroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithProratedMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingGroupedWithProratedMinimumPriceModelTypeConverter))] +public enum NewFloatingGroupedWithProratedMinimumPriceModelType +{ + GroupedWithProratedMinimum, +} + +sealed class NewFloatingGroupedWithProratedMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingGroupedWithProratedMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_with_prorated_minimum" => + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + _ => (NewFloatingGroupedWithProratedMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedWithProratedMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum => + "grouped_with_prorated_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingGroupedWithProratedMinimumPriceConversionRateConfigConverter))] +public record class NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingGroupedWithProratedMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingGroupedWithProratedMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 429f1dea..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 56ad80ec..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 31c14351..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingGroupedWithProratedMinimumPriceProperties = Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingGroupedWithProratedMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingGroupedWithProratedMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ModelType.cs deleted file mode 100644 index a5930b6a..00000000 --- a/src/Orb/Models/NewFloatingGroupedWithProratedMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingGroupedWithProratedMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithProratedMinimum = new( - "grouped_with_prorated_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithProratedMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_prorated_minimum" => Value.GroupedWithProratedMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixPrice.cs b/src/Orb/Models/NewFloatingMatrixPrice.cs index fe852f78..52d0caf2 100644 --- a/src/Orb/Models/NewFloatingMatrixPrice.cs +++ b/src/Orb/Models/NewFloatingMatrixPrice.cs @@ -1,36 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingMatrixPriceProperties = Orb.Models.NewFloatingMatrixPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingMatrixPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewFloatingMatrixPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingMatrixPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +32,8 @@ public sealed record class NewFloatingMatrixPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,51 +41,32 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } + /// + /// Configuration for matrix pricing + /// public required MatrixConfig MatrixConfig { - get - { - if (!this.Properties.TryGetValue("matrix_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_config"); - } - set { this.Properties["matrix_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "matrix_config"); } + init { JsonModel.Set(this._rawData, "matrix_config", value); } } - public required NewFloatingMatrixPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -109,15 +74,8 @@ public required MatrixConfig MatrixConfig /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -125,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,41 +118,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingMatrixPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingMatrixPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -230,21 +144,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +157,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +166,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,19 +175,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -313,21 +187,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,18 +200,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,29 +231,420 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingMatrixPrice() { } + public NewFloatingMatrixPrice(NewFloatingMatrixPrice newFloatingMatrixPrice) + : base(newFloatingMatrixPrice) { } + + public NewFloatingMatrixPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingMatrixPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingMatrixPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingMatrixPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingMatrixPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingMatrixPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingMatrixPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingMatrixPriceCadenceConverter))] +public enum NewFloatingMatrixPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingMatrixPriceCadenceConverter : JsonConverter +{ + public override NewFloatingMatrixPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingMatrixPriceCadence.Annual, + "semi_annual" => NewFloatingMatrixPriceCadence.SemiAnnual, + "monthly" => NewFloatingMatrixPriceCadence.Monthly, + "quarterly" => NewFloatingMatrixPriceCadence.Quarterly, + "one_time" => NewFloatingMatrixPriceCadence.OneTime, + "custom" => NewFloatingMatrixPriceCadence.Custom, + _ => (NewFloatingMatrixPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMatrixPriceCadence.Annual => "annual", + NewFloatingMatrixPriceCadence.SemiAnnual => "semi_annual", + NewFloatingMatrixPriceCadence.Monthly => "monthly", + NewFloatingMatrixPriceCadence.Quarterly => "quarterly", + NewFloatingMatrixPriceCadence.OneTime => "one_time", + NewFloatingMatrixPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingMatrixPriceModelTypeConverter))] +public enum NewFloatingMatrixPriceModelType +{ + Matrix, +} + +sealed class NewFloatingMatrixPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingMatrixPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix" => NewFloatingMatrixPriceModelType.Matrix, + _ => (NewFloatingMatrixPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMatrixPriceModelType.Matrix => "matrix", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingMatrixPriceConversionRateConfigConverter))] +public record class NewFloatingMatrixPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingMatrixPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMatrixPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMatrixPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingMatrixPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingMatrixPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingMatrixPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingMatrixPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingMatrixPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingMatrixPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingMatrixPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingMatrixPriceProperties/Cadence.cs deleted file mode 100644 index 6b819d66..00000000 --- a/src/Orb/Models/NewFloatingMatrixPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMatrixPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingMatrixPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 0f773837..00000000 --- a/src/Orb/Models/NewFloatingMatrixPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingMatrixPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMatrixPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingMatrixPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingMatrixPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 11a45d69..00000000 --- a/src/Orb/Models/NewFloatingMatrixPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingMatrixPriceProperties = Orb.Models.NewFloatingMatrixPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMatrixPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingMatrixPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingMatrixPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingMatrixPriceProperties/ModelType.cs deleted file mode 100644 index b3eaf331..00000000 --- a/src/Orb/Models/NewFloatingMatrixPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMatrixPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Matrix = new("matrix"); - - readonly string _value = value; - - public enum Value - { - Matrix, - } - - public Value Known() => - _value switch - { - "matrix" => Value.Matrix, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixWithAllocationPrice.cs b/src/Orb/Models/NewFloatingMatrixWithAllocationPrice.cs index 09f4f793..9fa24ba6 100644 --- a/src/Orb/Models/NewFloatingMatrixWithAllocationPrice.cs +++ b/src/Orb/Models/NewFloatingMatrixWithAllocationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingMatrixWithAllocationPriceProperties = Orb.Models.NewFloatingMatrixWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingMatrixWithAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingMatrixWithAllocationPrice, + NewFloatingMatrixWithAllocationPriceFromRaw + >) +)] +public sealed record class NewFloatingMatrixWithAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingMatrixWithAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingMatrixWithAllocationPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,60 +45,37 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } + /// + /// Configuration for matrix_with_allocation pricing + /// public required MatrixWithAllocationConfig MatrixWithAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "matrix_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_with_allocation_config"); - } - set - { - this.Properties["matrix_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_allocation_config" + ); } + init { JsonModel.Set(this._rawData, "matrix_with_allocation_config", value); } } - public required NewFloatingMatrixWithAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -118,15 +83,8 @@ public required MatrixWithAllocationConfig MatrixWithAllocationConfig /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -134,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -195,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingMatrixWithAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingMatrixWithAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -239,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -261,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -279,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -299,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -322,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -344,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -374,29 +240,426 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingMatrixWithAllocationPrice() { } + public NewFloatingMatrixWithAllocationPrice( + NewFloatingMatrixWithAllocationPrice newFloatingMatrixWithAllocationPrice + ) + : base(newFloatingMatrixWithAllocationPrice) { } + + public NewFloatingMatrixWithAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingMatrixWithAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingMatrixWithAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingMatrixWithAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingMatrixWithAllocationPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingMatrixWithAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingMatrixWithAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingMatrixWithAllocationPriceCadenceConverter))] +public enum NewFloatingMatrixWithAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingMatrixWithAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingMatrixWithAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingMatrixWithAllocationPriceCadence.Annual, + "semi_annual" => NewFloatingMatrixWithAllocationPriceCadence.SemiAnnual, + "monthly" => NewFloatingMatrixWithAllocationPriceCadence.Monthly, + "quarterly" => NewFloatingMatrixWithAllocationPriceCadence.Quarterly, + "one_time" => NewFloatingMatrixWithAllocationPriceCadence.OneTime, + "custom" => NewFloatingMatrixWithAllocationPriceCadence.Custom, + _ => (NewFloatingMatrixWithAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixWithAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMatrixWithAllocationPriceCadence.Annual => "annual", + NewFloatingMatrixWithAllocationPriceCadence.SemiAnnual => "semi_annual", + NewFloatingMatrixWithAllocationPriceCadence.Monthly => "monthly", + NewFloatingMatrixWithAllocationPriceCadence.Quarterly => "quarterly", + NewFloatingMatrixWithAllocationPriceCadence.OneTime => "one_time", + NewFloatingMatrixWithAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingMatrixWithAllocationPriceModelTypeConverter))] +public enum NewFloatingMatrixWithAllocationPriceModelType +{ + MatrixWithAllocation, +} + +sealed class NewFloatingMatrixWithAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingMatrixWithAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix_with_allocation" => + NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation, + _ => (NewFloatingMatrixWithAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixWithAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMatrixWithAllocationPriceModelType.MatrixWithAllocation => + "matrix_with_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingMatrixWithAllocationPriceConversionRateConfigConverter))] +public record class NewFloatingMatrixWithAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingMatrixWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMatrixWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMatrixWithAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixWithAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixWithAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingMatrixWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingMatrixWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixWithAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingMatrixWithAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingMatrixWithAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingMatrixWithAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingMatrixWithAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixWithAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 8ea3891f..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMatrixWithAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 8496f1dd..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingMatrixWithAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMatrixWithAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 921f1b76..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingMatrixWithAllocationPriceProperties = Orb.Models.NewFloatingMatrixWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMatrixWithAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingMatrixWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingMatrixWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 24e0ce9a..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMatrixWithAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithAllocation = new("matrix_with_allocation"); - - readonly string _value = value; - - public enum Value - { - MatrixWithAllocation, - } - - public Value Known() => - _value switch - { - "matrix_with_allocation" => Value.MatrixWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePrice.cs b/src/Orb/Models/NewFloatingMatrixWithDisplayNamePrice.cs index 448cd793..7441704a 100644 --- a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePrice.cs +++ b/src/Orb/Models/NewFloatingMatrixWithDisplayNamePrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingMatrixWithDisplayNamePriceProperties = Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingMatrixWithDisplayNamePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingMatrixWithDisplayNamePrice, + NewFloatingMatrixWithDisplayNamePriceFromRaw + >) +)] +public sealed record class NewFloatingMatrixWithDisplayNamePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingMatrixWithDisplayNamePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingMatrixWithDisplayNamePrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,61 +45,37 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Generic::Dictionary MatrixWithDisplayNameConfig + /// + /// Configuration for matrix_with_display_name pricing + /// + public required MatrixWithDisplayNameConfig MatrixWithDisplayNameConfig { get { - if ( - !this.Properties.TryGetValue( - "matrix_with_display_name_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_display_name_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("matrix_with_display_name_config"); - } - set - { - this.Properties["matrix_with_display_name_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_display_name_config" + ); } + init { JsonModel.Set(this._rawData, "matrix_with_display_name_config", value); } } - public required NewFloatingMatrixWithDisplayNamePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -119,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingMatrixWithDisplayNamePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingMatrixWithDisplayNamePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,27 +209,25 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; _ = this.ItemID; - foreach (var item in this.MatrixWithDisplayNameConfig.Values) - { - _ = item; - } + this.MatrixWithDisplayNameConfig.Validate(); this.ModelType.Validate(); _ = this.Name; _ = this.BillableMetricID; @@ -378,29 +240,587 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingMatrixWithDisplayNamePrice() { } + + public NewFloatingMatrixWithDisplayNamePrice( + NewFloatingMatrixWithDisplayNamePrice newFloatingMatrixWithDisplayNamePrice + ) + : base(newFloatingMatrixWithDisplayNamePrice) { } + + public NewFloatingMatrixWithDisplayNamePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingMatrixWithDisplayNamePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingMatrixWithDisplayNamePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingMatrixWithDisplayNamePriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingMatrixWithDisplayNamePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingMatrixWithDisplayNamePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingMatrixWithDisplayNamePriceCadenceConverter))] +public enum NewFloatingMatrixWithDisplayNamePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingMatrixWithDisplayNamePriceCadenceConverter + : JsonConverter +{ + public override NewFloatingMatrixWithDisplayNamePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingMatrixWithDisplayNamePriceCadence.Annual, + "semi_annual" => NewFloatingMatrixWithDisplayNamePriceCadence.SemiAnnual, + "monthly" => NewFloatingMatrixWithDisplayNamePriceCadence.Monthly, + "quarterly" => NewFloatingMatrixWithDisplayNamePriceCadence.Quarterly, + "one_time" => NewFloatingMatrixWithDisplayNamePriceCadence.OneTime, + "custom" => NewFloatingMatrixWithDisplayNamePriceCadence.Custom, + _ => (NewFloatingMatrixWithDisplayNamePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixWithDisplayNamePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingMatrixWithDisplayNamePriceCadence.Annual => "annual", + NewFloatingMatrixWithDisplayNamePriceCadence.SemiAnnual => "semi_annual", + NewFloatingMatrixWithDisplayNamePriceCadence.Monthly => "monthly", + NewFloatingMatrixWithDisplayNamePriceCadence.Quarterly => "quarterly", + NewFloatingMatrixWithDisplayNamePriceCadence.OneTime => "one_time", + NewFloatingMatrixWithDisplayNamePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for matrix_with_display_name pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class MatrixWithDisplayNameConfig : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string Dimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension"); } + init { JsonModel.Set(this._rawData, "dimension", value); } + } + + /// + /// Apply per unit pricing to each dimension value + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "unit_amounts" + ); } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } } - public NewFloatingMatrixWithDisplayNamePrice() { } + /// + public override void Validate() + { + _ = this.Dimension; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public MatrixWithDisplayNameConfig() { } + + public MatrixWithDisplayNameConfig(MatrixWithDisplayNameConfig matrixWithDisplayNameConfig) + : base(matrixWithDisplayNameConfig) { } + + public MatrixWithDisplayNameConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingMatrixWithDisplayNamePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + MatrixWithDisplayNameConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingMatrixWithDisplayNamePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static MatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameConfigFromRaw : IFromRawJson +{ + /// + public MatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithDisplayNameConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a unit amount item +/// +[JsonConverter( + typeof(JsonModelConverter< + MatrixWithDisplayNameConfigUnitAmount, + MatrixWithDisplayNameConfigUnitAmountFromRaw + >) +)] +public sealed record class MatrixWithDisplayNameConfigUnitAmount : JsonModel +{ + /// + /// The dimension value + /// + public required string DimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension_value"); } + init { JsonModel.Set(this._rawData, "dimension_value", value); } + } + + /// + /// Display name for this dimension value + /// + public required string DisplayName + { + get { return JsonModel.GetNotNullClass(this.RawData, "display_name"); } + init { JsonModel.Set(this._rawData, "display_name", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.DimensionValue; + _ = this.DisplayName; + _ = this.UnitAmount; + } + + public MatrixWithDisplayNameConfigUnitAmount() { } + + public MatrixWithDisplayNameConfigUnitAmount( + MatrixWithDisplayNameConfigUnitAmount matrixWithDisplayNameConfigUnitAmount + ) + : base(matrixWithDisplayNameConfigUnitAmount) { } + + public MatrixWithDisplayNameConfigUnitAmount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithDisplayNameConfigUnitAmount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameConfigUnitAmountFromRaw + : IFromRawJson +{ + /// + public MatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithDisplayNameConfigUnitAmount.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingMatrixWithDisplayNamePriceModelTypeConverter))] +public enum NewFloatingMatrixWithDisplayNamePriceModelType +{ + MatrixWithDisplayName, +} + +sealed class NewFloatingMatrixWithDisplayNamePriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingMatrixWithDisplayNamePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix_with_display_name" => + NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + _ => (NewFloatingMatrixWithDisplayNamePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixWithDisplayNamePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName => + "matrix_with_display_name", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingMatrixWithDisplayNamePriceConversionRateConfigConverter))] +public record class NewFloatingMatrixWithDisplayNamePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingMatrixWithDisplayNamePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMatrixWithDisplayNamePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMatrixWithDisplayNamePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixWithDisplayNamePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixWithDisplayNamePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingMatrixWithDisplayNamePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingMatrixWithDisplayNamePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMatrixWithDisplayNamePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingMatrixWithDisplayNamePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingMatrixWithDisplayNamePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingMatrixWithDisplayNamePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingMatrixWithDisplayNamePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMatrixWithDisplayNamePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/Cadence.cs deleted file mode 100644 index 80e64139..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index f09bb7e7..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 25032694..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingMatrixWithDisplayNamePriceProperties = Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingMatrixWithDisplayNamePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingMatrixWithDisplayNamePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ModelType.cs deleted file mode 100644 index 731aa49f..00000000 --- a/src/Orb/Models/NewFloatingMatrixWithDisplayNamePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMatrixWithDisplayNamePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithDisplayName = new("matrix_with_display_name"); - - readonly string _value = value; - - public enum Value - { - MatrixWithDisplayName, - } - - public Value Known() => - _value switch - { - "matrix_with_display_name" => Value.MatrixWithDisplayName, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePrice.cs b/src/Orb/Models/NewFloatingMaxGroupTieredPackagePrice.cs index d4157cdc..2b5b530c 100644 --- a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePrice.cs +++ b/src/Orb/Models/NewFloatingMaxGroupTieredPackagePrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingMaxGroupTieredPackagePriceProperties = Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingMaxGroupTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingMaxGroupTieredPackagePrice, + NewFloatingMaxGroupTieredPackagePriceFromRaw + >) +)] +public sealed record class NewFloatingMaxGroupTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingMaxGroupTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingMaxGroupTieredPackagePrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,61 +45,37 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Generic::Dictionary MaxGroupTieredPackageConfig + /// + /// Configuration for max_group_tiered_package pricing + /// + public required MaxGroupTieredPackageConfig MaxGroupTieredPackageConfig { get { - if ( - !this.Properties.TryGetValue( - "max_group_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "max_group_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("max_group_tiered_package_config"); - } - set - { - this.Properties["max_group_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "max_group_tiered_package_config" + ); } + init { JsonModel.Set(this._rawData, "max_group_tiered_package_config", value); } } - public required NewFloatingMaxGroupTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -119,15 +83,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingMaxGroupTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingMaxGroupTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,27 +209,25 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.Currency; _ = this.ItemID; - foreach (var item in this.MaxGroupTieredPackageConfig.Values) - { - _ = item; - } + this.MaxGroupTieredPackageConfig.Validate(); this.ModelType.Validate(); _ = this.Name; _ = this.BillableMetricID; @@ -378,29 +240,586 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingMaxGroupTieredPackagePrice() { } + + public NewFloatingMaxGroupTieredPackagePrice( + NewFloatingMaxGroupTieredPackagePrice newFloatingMaxGroupTieredPackagePrice + ) + : base(newFloatingMaxGroupTieredPackagePrice) { } + + public NewFloatingMaxGroupTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingMaxGroupTieredPackagePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingMaxGroupTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingMaxGroupTieredPackagePriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingMaxGroupTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingMaxGroupTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingMaxGroupTieredPackagePriceCadenceConverter))] +public enum NewFloatingMaxGroupTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingMaxGroupTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewFloatingMaxGroupTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingMaxGroupTieredPackagePriceCadence.Annual, + "semi_annual" => NewFloatingMaxGroupTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewFloatingMaxGroupTieredPackagePriceCadence.Monthly, + "quarterly" => NewFloatingMaxGroupTieredPackagePriceCadence.Quarterly, + "one_time" => NewFloatingMaxGroupTieredPackagePriceCadence.OneTime, + "custom" => NewFloatingMaxGroupTieredPackagePriceCadence.Custom, + _ => (NewFloatingMaxGroupTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMaxGroupTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingMaxGroupTieredPackagePriceCadence.Annual => "annual", + NewFloatingMaxGroupTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewFloatingMaxGroupTieredPackagePriceCadence.Monthly => "monthly", + NewFloatingMaxGroupTieredPackagePriceCadence.Quarterly => "quarterly", + NewFloatingMaxGroupTieredPackagePriceCadence.OneTime => "one_time", + NewFloatingMaxGroupTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for max_group_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class MaxGroupTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering the group with the highest value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing to the largest group after grouping with the provided key. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); } + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewFloatingMaxGroupTieredPackagePrice() { } + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public MaxGroupTieredPackageConfig() { } + + public MaxGroupTieredPackageConfig(MaxGroupTieredPackageConfig maxGroupTieredPackageConfig) + : base(maxGroupTieredPackageConfig) { } + + public MaxGroupTieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingMaxGroupTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + MaxGroupTieredPackageConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingMaxGroupTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static MaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageConfigFromRaw : IFromRawJson +{ + /// + public MaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaxGroupTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + MaxGroupTieredPackageConfigTier, + MaxGroupTieredPackageConfigTierFromRaw + >) +)] +public sealed record class MaxGroupTieredPackageConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public MaxGroupTieredPackageConfigTier() { } + + public MaxGroupTieredPackageConfigTier( + MaxGroupTieredPackageConfigTier maxGroupTieredPackageConfigTier + ) + : base(maxGroupTieredPackageConfigTier) { } + + public MaxGroupTieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaxGroupTieredPackageConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageConfigTierFromRaw : IFromRawJson +{ + /// + public MaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaxGroupTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingMaxGroupTieredPackagePriceModelTypeConverter))] +public enum NewFloatingMaxGroupTieredPackagePriceModelType +{ + MaxGroupTieredPackage, +} + +sealed class NewFloatingMaxGroupTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingMaxGroupTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "max_group_tiered_package" => + NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + _ => (NewFloatingMaxGroupTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMaxGroupTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage => + "max_group_tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingMaxGroupTieredPackagePriceConversionRateConfigConverter))] +public record class NewFloatingMaxGroupTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingMaxGroupTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMaxGroupTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMaxGroupTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMaxGroupTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMaxGroupTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingMaxGroupTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingMaxGroupTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMaxGroupTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingMaxGroupTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingMaxGroupTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingMaxGroupTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingMaxGroupTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMaxGroupTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index ffae3576..00000000 --- a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index f8f2c680..00000000 --- a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index cd18edec..00000000 --- a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingMaxGroupTieredPackagePriceProperties = Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingMaxGroupTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingMaxGroupTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index a06583d6..00000000 --- a/src/Orb/Models/NewFloatingMaxGroupTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingMaxGroupTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MaxGroupTieredPackage = new("max_group_tiered_package"); - - readonly string _value = value; - - public enum Value - { - MaxGroupTieredPackage, - } - - public Value Known() => - _value switch - { - "max_group_tiered_package" => Value.MaxGroupTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingMinimumCompositePrice.cs b/src/Orb/Models/NewFloatingMinimumCompositePrice.cs new file mode 100644 index 00000000..f29c0fdf --- /dev/null +++ b/src/Orb/Models/NewFloatingMinimumCompositePrice.cs @@ -0,0 +1,734 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models; + +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingMinimumCompositePrice, + NewFloatingMinimumCompositePriceFromRaw + >) +)] +public sealed record class NewFloatingMinimumCompositePrice : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// Configuration for minimum pricing + /// + public required MinimumConfig MinimumConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_config"); } + init { JsonModel.Set(this._rawData, "minimum_config", value); } + } + + /// + /// The pricing model type + /// + public required ApiEnum ModelType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); + } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public NewFloatingMinimumCompositePriceConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + this.MinimumConfig.Validate(); + this.ModelType.Validate(); + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public NewFloatingMinimumCompositePrice() { } + + public NewFloatingMinimumCompositePrice( + NewFloatingMinimumCompositePrice newFloatingMinimumCompositePrice + ) + : base(newFloatingMinimumCompositePrice) { } + + public NewFloatingMinimumCompositePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingMinimumCompositePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingMinimumCompositePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingMinimumCompositePriceFromRaw : IFromRawJson +{ + /// + public NewFloatingMinimumCompositePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingMinimumCompositePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingMinimumCompositePriceCadenceConverter))] +public enum NewFloatingMinimumCompositePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingMinimumCompositePriceCadenceConverter + : JsonConverter +{ + public override NewFloatingMinimumCompositePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingMinimumCompositePriceCadence.Annual, + "semi_annual" => NewFloatingMinimumCompositePriceCadence.SemiAnnual, + "monthly" => NewFloatingMinimumCompositePriceCadence.Monthly, + "quarterly" => NewFloatingMinimumCompositePriceCadence.Quarterly, + "one_time" => NewFloatingMinimumCompositePriceCadence.OneTime, + "custom" => NewFloatingMinimumCompositePriceCadence.Custom, + _ => (NewFloatingMinimumCompositePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMinimumCompositePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMinimumCompositePriceCadence.Annual => "annual", + NewFloatingMinimumCompositePriceCadence.SemiAnnual => "semi_annual", + NewFloatingMinimumCompositePriceCadence.Monthly => "monthly", + NewFloatingMinimumCompositePriceCadence.Quarterly => "quarterly", + NewFloatingMinimumCompositePriceCadence.OneTime => "one_time", + NewFloatingMinimumCompositePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for minimum pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MinimumConfig : JsonModel +{ + /// + /// The minimum amount to apply + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// If true, subtotals from this price are prorated based on the service period + /// + public bool? Prorated + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorated"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorated", value); + } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.Prorated; + } + + public MinimumConfig() { } + + public MinimumConfig(MinimumConfig minimumConfig) + : base(minimumConfig) { } + + public MinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MinimumConfig FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public MinimumConfig(string minimumAmount) + : this() + { + this.MinimumAmount = minimumAmount; + } +} + +class MinimumConfigFromRaw : IFromRawJson +{ + /// + public MinimumConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + MinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingMinimumCompositePriceModelTypeConverter))] +public enum NewFloatingMinimumCompositePriceModelType +{ + Minimum, +} + +sealed class NewFloatingMinimumCompositePriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingMinimumCompositePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "minimum" => NewFloatingMinimumCompositePriceModelType.Minimum, + _ => (NewFloatingMinimumCompositePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMinimumCompositePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingMinimumCompositePriceModelType.Minimum => "minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingMinimumCompositePriceConversionRateConfigConverter))] +public record class NewFloatingMinimumCompositePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingMinimumCompositePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMinimumCompositePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingMinimumCompositePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMinimumCompositePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMinimumCompositePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingMinimumCompositePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingMinimumCompositePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingMinimumCompositePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingMinimumCompositePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingMinimumCompositePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingMinimumCompositePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingMinimumCompositePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingMinimumCompositePriceConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Models/NewFloatingPackagePrice.cs b/src/Orb/Models/NewFloatingPackagePrice.cs index c10dac1a..d16c949c 100644 --- a/src/Orb/Models/NewFloatingPackagePrice.cs +++ b/src/Orb/Models/NewFloatingPackagePrice.cs @@ -1,36 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingPackagePriceProperties = Orb.Models.NewFloatingPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewFloatingPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +32,8 @@ public sealed record class NewFloatingPackagePrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +41,23 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,31 +65,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// + /// Configuration for package pricing + /// public required PackageConfig PackageConfig { - get - { - if (!this.Properties.TryGetValue("package_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("package_config"); - } - set { this.Properties["package_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "package_config"); } + init { JsonModel.Set(this._rawData, "package_config", value); } } /// @@ -125,60 +83,34 @@ public required PackageConfig PackageConfig /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,41 +118,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -230,21 +144,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +157,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +166,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,19 +175,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -313,21 +187,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,18 +200,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,29 +231,420 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingPackagePrice() { } + public NewFloatingPackagePrice(NewFloatingPackagePrice newFloatingPackagePrice) + : base(newFloatingPackagePrice) { } + + public NewFloatingPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingPackagePriceFromRaw : IFromRawJson +{ + /// + public NewFloatingPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingPackagePriceCadenceConverter))] +public enum NewFloatingPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingPackagePriceCadenceConverter : JsonConverter +{ + public override NewFloatingPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingPackagePriceCadence.Annual, + "semi_annual" => NewFloatingPackagePriceCadence.SemiAnnual, + "monthly" => NewFloatingPackagePriceCadence.Monthly, + "quarterly" => NewFloatingPackagePriceCadence.Quarterly, + "one_time" => NewFloatingPackagePriceCadence.OneTime, + "custom" => NewFloatingPackagePriceCadence.Custom, + _ => (NewFloatingPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingPackagePriceCadence.Annual => "annual", + NewFloatingPackagePriceCadence.SemiAnnual => "semi_annual", + NewFloatingPackagePriceCadence.Monthly => "monthly", + NewFloatingPackagePriceCadence.Quarterly => "quarterly", + NewFloatingPackagePriceCadence.OneTime => "one_time", + NewFloatingPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingPackagePriceModelTypeConverter))] +public enum NewFloatingPackagePriceModelType +{ + Package, +} + +sealed class NewFloatingPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "package" => NewFloatingPackagePriceModelType.Package, + _ => (NewFloatingPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingPackagePriceModelType.Package => "package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingPackagePriceConversionRateConfigConverter))] +public record class NewFloatingPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingPackagePriceProperties/Cadence.cs deleted file mode 100644 index 9c8ef918..00000000 --- a/src/Orb/Models/NewFloatingPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index e10a17c1..00000000 --- a/src/Orb/Models/NewFloatingPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index b0c5e587..00000000 --- a/src/Orb/Models/NewFloatingPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingPackagePriceProperties = Orb.Models.NewFloatingPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingPackagePriceProperties/ModelType.cs deleted file mode 100644 index 43dc02e4..00000000 --- a/src/Orb/Models/NewFloatingPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Package = new("package"); - - readonly string _value = value; - - public enum Value - { - Package, - } - - public Value Known() => - _value switch - { - "package" => Value.Package, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingPackageWithAllocationPrice.cs b/src/Orb/Models/NewFloatingPackageWithAllocationPrice.cs index 9c0343aa..241d8316 100644 --- a/src/Orb/Models/NewFloatingPackageWithAllocationPrice.cs +++ b/src/Orb/Models/NewFloatingPackageWithAllocationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingPackageWithAllocationPriceProperties = Orb.Models.NewFloatingPackageWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingPackageWithAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingPackageWithAllocationPrice, + NewFloatingPackageWithAllocationPriceFromRaw + >) +)] +public sealed record class NewFloatingPackageWithAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingPackageWithAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingPackageWithAllocationPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingPackageWithAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,41 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary PackageWithAllocationConfig + /// + /// Configuration for package_with_allocation pricing + /// + public required PackageWithAllocationConfig PackageWithAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "package_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "package_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("package_with_allocation_config"); - } - set - { - this.Properties["package_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "package_with_allocation_config" + ); } + init { JsonModel.Set(this._rawData, "package_with_allocation_config", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingPackageWithAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingPackageWithAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -364,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.PackageWithAllocationConfig.Values) - { - _ = item; - } + this.PackageWithAllocationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -378,29 +240,504 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingPackageWithAllocationPrice() { } + public NewFloatingPackageWithAllocationPrice( + NewFloatingPackageWithAllocationPrice newFloatingPackageWithAllocationPrice + ) + : base(newFloatingPackageWithAllocationPrice) { } + + public NewFloatingPackageWithAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingPackageWithAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingPackageWithAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingPackageWithAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingPackageWithAllocationPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingPackageWithAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingPackageWithAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingPackageWithAllocationPriceCadenceConverter))] +public enum NewFloatingPackageWithAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingPackageWithAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingPackageWithAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingPackageWithAllocationPriceCadence.Annual, + "semi_annual" => NewFloatingPackageWithAllocationPriceCadence.SemiAnnual, + "monthly" => NewFloatingPackageWithAllocationPriceCadence.Monthly, + "quarterly" => NewFloatingPackageWithAllocationPriceCadence.Quarterly, + "one_time" => NewFloatingPackageWithAllocationPriceCadence.OneTime, + "custom" => NewFloatingPackageWithAllocationPriceCadence.Custom, + _ => (NewFloatingPackageWithAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingPackageWithAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingPackageWithAllocationPriceCadence.Annual => "annual", + NewFloatingPackageWithAllocationPriceCadence.SemiAnnual => "semi_annual", + NewFloatingPackageWithAllocationPriceCadence.Monthly => "monthly", + NewFloatingPackageWithAllocationPriceCadence.Quarterly => "quarterly", + NewFloatingPackageWithAllocationPriceCadence.OneTime => "one_time", + NewFloatingPackageWithAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingPackageWithAllocationPriceModelTypeConverter))] +public enum NewFloatingPackageWithAllocationPriceModelType +{ + PackageWithAllocation, +} + +sealed class NewFloatingPackageWithAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingPackageWithAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "package_with_allocation" => + NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation, + _ => (NewFloatingPackageWithAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingPackageWithAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingPackageWithAllocationPriceModelType.PackageWithAllocation => + "package_with_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for package_with_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PackageWithAllocationConfig : JsonModel +{ + /// + /// Usage allocation + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// Price per package + /// + public required string PackageAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_amount"); } + init { JsonModel.Set(this._rawData, "package_amount", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.PackageAmount; + _ = this.PackageSize; + } + + public PackageWithAllocationConfig() { } + + public PackageWithAllocationConfig(PackageWithAllocationConfig packageWithAllocationConfig) + : base(packageWithAllocationConfig) { } + + public PackageWithAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PackageWithAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageWithAllocationConfigFromRaw : IFromRawJson +{ + /// + public PackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PackageWithAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingPackageWithAllocationPriceConversionRateConfigConverter))] +public record class NewFloatingPackageWithAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingPackageWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingPackageWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingPackageWithAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingPackageWithAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingPackageWithAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingPackageWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingPackageWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingPackageWithAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingPackageWithAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingPackageWithAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingPackageWithAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingPackageWithAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingPackageWithAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 99fd1f8f..00000000 --- a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingPackageWithAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 48666ecc..00000000 --- a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingPackageWithAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingPackageWithAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 39adfb02..00000000 --- a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingPackageWithAllocationPriceProperties = Orb.Models.NewFloatingPackageWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingPackageWithAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingPackageWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingPackageWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ModelType.cs deleted file mode 100644 index b3750af0..00000000 --- a/src/Orb/Models/NewFloatingPackageWithAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingPackageWithAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType PackageWithAllocation = new("package_with_allocation"); - - readonly string _value = value; - - public enum Value - { - PackageWithAllocation, - } - - public Value Known() => - _value switch - { - "package_with_allocation" => Value.PackageWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPrice.cs b/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPrice.cs index 86ab3508..14dc125c 100644 --- a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPrice.cs +++ b/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingScalableMatrixWithTieredPricingPriceProperties = Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingScalableMatrixWithTieredPricingPrice, + NewFloatingScalableMatrixWithTieredPricingPriceFromRaw + >) )] -public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingScalableMatrixWithTieredPricingPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,18 +36,8 @@ public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -59,35 +45,25 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingScalableMatrixWithTieredPricingPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum< + string, + NewFloatingScalableMatrixWithTieredPricingPriceModelType + > ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -95,47 +71,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithTieredPricingConfig + /// + /// Configuration for scalable_matrix_with_tiered_pricing pricing + /// + public required ScalableMatrixWithTieredPricingConfig ScalableMatrixWithTieredPricingConfig { get { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_tiered_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_tiered_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_tiered_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_tiered_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_tiered_pricing_config" + ); } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_tiered_pricing_config", value); } } /// @@ -143,60 +95,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -204,41 +130,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -248,21 +156,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -270,17 +169,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -288,19 +178,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -308,19 +187,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -331,21 +199,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -353,18 +212,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -372,10 +232,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ScalableMatrixWithTieredPricingConfig.Values) - { - _ = item; - } + this.ScalableMatrixWithTieredPricingConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -386,31 +243,697 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingScalableMatrixWithTieredPricingPrice() { } + + public NewFloatingScalableMatrixWithTieredPricingPrice( + NewFloatingScalableMatrixWithTieredPricingPrice newFloatingScalableMatrixWithTieredPricingPrice + ) + : base(newFloatingScalableMatrixWithTieredPricingPrice) { } + + public NewFloatingScalableMatrixWithTieredPricingPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingScalableMatrixWithTieredPricingPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingScalableMatrixWithTieredPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingScalableMatrixWithTieredPricingPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingScalableMatrixWithTieredPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingScalableMatrixWithTieredPricingPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingScalableMatrixWithTieredPricingPriceCadenceConverter))] +public enum NewFloatingScalableMatrixWithTieredPricingPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingScalableMatrixWithTieredPricingPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingScalableMatrixWithTieredPricingPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual, + "semi_annual" => NewFloatingScalableMatrixWithTieredPricingPriceCadence.SemiAnnual, + "monthly" => NewFloatingScalableMatrixWithTieredPricingPriceCadence.Monthly, + "quarterly" => NewFloatingScalableMatrixWithTieredPricingPriceCadence.Quarterly, + "one_time" => NewFloatingScalableMatrixWithTieredPricingPriceCadence.OneTime, + "custom" => NewFloatingScalableMatrixWithTieredPricingPriceCadence.Custom, + _ => (NewFloatingScalableMatrixWithTieredPricingPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingScalableMatrixWithTieredPricingPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingScalableMatrixWithTieredPricingPriceCadence.Annual => "annual", + NewFloatingScalableMatrixWithTieredPricingPriceCadence.SemiAnnual => "semi_annual", + NewFloatingScalableMatrixWithTieredPricingPriceCadence.Monthly => "monthly", + NewFloatingScalableMatrixWithTieredPricingPriceCadence.Quarterly => "quarterly", + NewFloatingScalableMatrixWithTieredPricingPriceCadence.OneTime => "one_time", + NewFloatingScalableMatrixWithTieredPricingPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingScalableMatrixWithTieredPricingPriceModelTypeConverter))] +public enum NewFloatingScalableMatrixWithTieredPricingPriceModelType +{ + ScalableMatrixWithTieredPricing, +} + +sealed class NewFloatingScalableMatrixWithTieredPricingPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingScalableMatrixWithTieredPricingPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "scalable_matrix_with_tiered_pricing" => + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + _ => (NewFloatingScalableMatrixWithTieredPricingPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingScalableMatrixWithTieredPricingPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing => + "scalable_matrix_with_tiered_pricing", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_tiered_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricingConfig, + ScalableMatrixWithTieredPricingConfigFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingConfig : JsonModel +{ + /// + /// Used for the scalable matrix first dimension + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "matrix_scaling_factors" + ); } + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } } - public NewFloatingScalableMatrixWithTieredPricingPrice() { } + /// + /// Tier pricing structure + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// Used for the scalable matrix second dimension (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.SecondDimension; + } + + public ScalableMatrixWithTieredPricingConfig() { } + + public ScalableMatrixWithTieredPricingConfig( + ScalableMatrixWithTieredPricingConfig scalableMatrixWithTieredPricingConfig + ) + : base(scalableMatrixWithTieredPricingConfig) { } + + public ScalableMatrixWithTieredPricingConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingConfigFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithTieredPricingConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MatrixScalingFactor : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public MatrixScalingFactor() { } + + public MatrixScalingFactor(MatrixScalingFactor matrixScalingFactor) + : base(matrixScalingFactor) { } + + public MatrixScalingFactor(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingScalableMatrixWithTieredPricingPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + MatrixScalingFactor(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixScalingFactorFromRaw : IFromRawJson +{ + /// + public MatrixScalingFactor FromRawUnchecked(IReadOnlyDictionary rawData) => + MatrixScalingFactor.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier entry with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricingConfigTier, + ScalableMatrixWithTieredPricingConfigTierFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public ScalableMatrixWithTieredPricingConfigTier() { } + + public ScalableMatrixWithTieredPricingConfigTier( + ScalableMatrixWithTieredPricingConfigTier scalableMatrixWithTieredPricingConfigTier + ) + : base(scalableMatrixWithTieredPricingConfigTier) { } + + public ScalableMatrixWithTieredPricingConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingScalableMatrixWithTieredPricingPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static ScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingConfigTierFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithTieredPricingConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfigConverter) +)] +public record class NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingScalableMatrixWithTieredPricingPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/Cadence.cs deleted file mode 100644 index 62ea41fc..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 3761223a..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index fa5d0857..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingScalableMatrixWithTieredPricingPriceProperties = Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ModelType.cs deleted file mode 100644 index fc6fa0b9..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithTieredPricingPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingScalableMatrixWithTieredPricingPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithTieredPricing = new( - "scalable_matrix_with_tiered_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithTieredPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_tiered_pricing" => Value.ScalableMatrixWithTieredPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPrice.cs b/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPrice.cs index 3cac1556..fb54dc43 100644 --- a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPrice.cs +++ b/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingScalableMatrixWithUnitPricingPriceProperties = Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingScalableMatrixWithUnitPricingPrice, + NewFloatingScalableMatrixWithUnitPricingPriceFromRaw + >) )] -public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingScalableMatrixWithUnitPricingPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,18 +36,8 @@ public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -59,35 +45,25 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingScalableMatrixWithUnitPricingPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum< + string, + NewFloatingScalableMatrixWithUnitPricingPriceModelType + > ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -95,47 +71,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithUnitPricingConfig + /// + /// Configuration for scalable_matrix_with_unit_pricing pricing + /// + public required ScalableMatrixWithUnitPricingConfig ScalableMatrixWithUnitPricingConfig { get { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_unit_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_unit_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_unit_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_unit_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_unit_pricing_config" + ); } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_unit_pricing_config", value); } } /// @@ -143,60 +95,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -204,41 +130,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -248,21 +156,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -270,17 +169,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -288,19 +178,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -308,19 +187,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -331,21 +199,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -353,18 +212,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -372,10 +232,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ScalableMatrixWithUnitPricingConfig.Values) - { - _ = item; - } + this.ScalableMatrixWithUnitPricingConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -386,31 +243,631 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingScalableMatrixWithUnitPricingPrice() { } + + public NewFloatingScalableMatrixWithUnitPricingPrice( + NewFloatingScalableMatrixWithUnitPricingPrice newFloatingScalableMatrixWithUnitPricingPrice + ) + : base(newFloatingScalableMatrixWithUnitPricingPrice) { } + + public NewFloatingScalableMatrixWithUnitPricingPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingScalableMatrixWithUnitPricingPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingScalableMatrixWithUnitPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingScalableMatrixWithUnitPricingPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingScalableMatrixWithUnitPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingScalableMatrixWithUnitPricingPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingScalableMatrixWithUnitPricingPriceCadenceConverter))] +public enum NewFloatingScalableMatrixWithUnitPricingPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingScalableMatrixWithUnitPricingPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingScalableMatrixWithUnitPricingPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual, + "semi_annual" => NewFloatingScalableMatrixWithUnitPricingPriceCadence.SemiAnnual, + "monthly" => NewFloatingScalableMatrixWithUnitPricingPriceCadence.Monthly, + "quarterly" => NewFloatingScalableMatrixWithUnitPricingPriceCadence.Quarterly, + "one_time" => NewFloatingScalableMatrixWithUnitPricingPriceCadence.OneTime, + "custom" => NewFloatingScalableMatrixWithUnitPricingPriceCadence.Custom, + _ => (NewFloatingScalableMatrixWithUnitPricingPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingScalableMatrixWithUnitPricingPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingScalableMatrixWithUnitPricingPriceCadence.Annual => "annual", + NewFloatingScalableMatrixWithUnitPricingPriceCadence.SemiAnnual => "semi_annual", + NewFloatingScalableMatrixWithUnitPricingPriceCadence.Monthly => "monthly", + NewFloatingScalableMatrixWithUnitPricingPriceCadence.Quarterly => "quarterly", + NewFloatingScalableMatrixWithUnitPricingPriceCadence.OneTime => "one_time", + NewFloatingScalableMatrixWithUnitPricingPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingScalableMatrixWithUnitPricingPriceModelTypeConverter))] +public enum NewFloatingScalableMatrixWithUnitPricingPriceModelType +{ + ScalableMatrixWithUnitPricing, +} + +sealed class NewFloatingScalableMatrixWithUnitPricingPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingScalableMatrixWithUnitPricingPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "scalable_matrix_with_unit_pricing" => + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + _ => (NewFloatingScalableMatrixWithUnitPricingPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingScalableMatrixWithUnitPricingPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing => + "scalable_matrix_with_unit_pricing", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_unit_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithUnitPricingConfig, + ScalableMatrixWithUnitPricingConfigFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingConfig : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); } + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } } - public NewFloatingScalableMatrixWithUnitPricingPrice() { } + /// + /// The final unit price to rate against the output of the matrix + /// + public required string UnitPrice + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_price"); } + init { JsonModel.Set(this._rawData, "unit_price", value); } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + /// Used to determine the unit rate (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + _ = this.UnitPrice; + _ = this.Prorate; + _ = this.SecondDimension; + } + + public ScalableMatrixWithUnitPricingConfig() { } + + public ScalableMatrixWithUnitPricingConfig( + ScalableMatrixWithUnitPricingConfig scalableMatrixWithUnitPricingConfig + ) + : base(scalableMatrixWithUnitPricingConfig) { } + + public ScalableMatrixWithUnitPricingConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingScalableMatrixWithUnitPricingPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingConfigFromRaw : IFromRawJson +{ + /// + public ScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithUnitPricingConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithUnitPricingConfigMatrixScalingFactor, + ScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor() { } + + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + ScalableMatrixWithUnitPricingConfigMatrixScalingFactor scalableMatrixWithUnitPricingConfigMatrixScalingFactor + ) + : base(scalableMatrixWithUnitPricingConfigMatrixScalingFactor) { } + + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingScalableMatrixWithUnitPricingPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static ScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithUnitPricingConfigMatrixScalingFactor.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfigConverter))] +public record class NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingScalableMatrixWithUnitPricingPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/Cadence.cs deleted file mode 100644 index d98eeba1..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 3caa82c9..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 426e87df..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingScalableMatrixWithUnitPricingPriceProperties = Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ModelType.cs deleted file mode 100644 index f596f46a..00000000 --- a/src/Orb/Models/NewFloatingScalableMatrixWithUnitPricingPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingScalableMatrixWithUnitPricingPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithUnitPricing = new( - "scalable_matrix_with_unit_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithUnitPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_unit_pricing" => Value.ScalableMatrixWithUnitPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingThresholdTotalAmountPrice.cs b/src/Orb/Models/NewFloatingThresholdTotalAmountPrice.cs index 272326d3..98ef947e 100644 --- a/src/Orb/Models/NewFloatingThresholdTotalAmountPrice.cs +++ b/src/Orb/Models/NewFloatingThresholdTotalAmountPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingThresholdTotalAmountPriceProperties = Orb.Models.NewFloatingThresholdTotalAmountPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingThresholdTotalAmountPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingThresholdTotalAmountPrice, + NewFloatingThresholdTotalAmountPriceFromRaw + >) +)] +public sealed record class NewFloatingThresholdTotalAmountPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingThresholdTotalAmountPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingThresholdTotalAmountPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingThresholdTotalAmountPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,41 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary ThresholdTotalAmountConfig + /// + /// Configuration for threshold_total_amount pricing + /// + public required ThresholdTotalAmountConfig ThresholdTotalAmountConfig { get { - if ( - !this.Properties.TryGetValue( - "threshold_total_amount_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "threshold_total_amount_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("threshold_total_amount_config"); - } - set - { - this.Properties["threshold_total_amount_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "threshold_total_amount_config" + ); } + init { JsonModel.Set(this._rawData, "threshold_total_amount_config", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingThresholdTotalAmountPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingThresholdTotalAmountPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -364,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ThresholdTotalAmountConfig.Values) - { - _ = item; - } + this.ThresholdTotalAmountConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -378,29 +240,576 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingThresholdTotalAmountPrice() { } + + public NewFloatingThresholdTotalAmountPrice( + NewFloatingThresholdTotalAmountPrice newFloatingThresholdTotalAmountPrice + ) + : base(newFloatingThresholdTotalAmountPrice) { } + + public NewFloatingThresholdTotalAmountPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingThresholdTotalAmountPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingThresholdTotalAmountPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingThresholdTotalAmountPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingThresholdTotalAmountPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingThresholdTotalAmountPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingThresholdTotalAmountPriceCadenceConverter))] +public enum NewFloatingThresholdTotalAmountPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingThresholdTotalAmountPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingThresholdTotalAmountPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingThresholdTotalAmountPriceCadence.Annual, + "semi_annual" => NewFloatingThresholdTotalAmountPriceCadence.SemiAnnual, + "monthly" => NewFloatingThresholdTotalAmountPriceCadence.Monthly, + "quarterly" => NewFloatingThresholdTotalAmountPriceCadence.Quarterly, + "one_time" => NewFloatingThresholdTotalAmountPriceCadence.OneTime, + "custom" => NewFloatingThresholdTotalAmountPriceCadence.Custom, + _ => (NewFloatingThresholdTotalAmountPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingThresholdTotalAmountPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingThresholdTotalAmountPriceCadence.Annual => "annual", + NewFloatingThresholdTotalAmountPriceCadence.SemiAnnual => "semi_annual", + NewFloatingThresholdTotalAmountPriceCadence.Monthly => "monthly", + NewFloatingThresholdTotalAmountPriceCadence.Quarterly => "quarterly", + NewFloatingThresholdTotalAmountPriceCadence.OneTime => "one_time", + NewFloatingThresholdTotalAmountPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingThresholdTotalAmountPriceModelTypeConverter))] +public enum NewFloatingThresholdTotalAmountPriceModelType +{ + ThresholdTotalAmount, +} + +sealed class NewFloatingThresholdTotalAmountPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingThresholdTotalAmountPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "threshold_total_amount" => + NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + _ => (NewFloatingThresholdTotalAmountPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingThresholdTotalAmountPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingThresholdTotalAmountPriceModelType.ThresholdTotalAmount => + "threshold_total_amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for threshold_total_amount pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ThresholdTotalAmountConfig : JsonModel +{ + /// + /// When the quantity consumed passes a provided threshold, the configured total + /// will be charged + /// + public required IReadOnlyList ConsumptionTable + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "consumption_table" + ); } + init { JsonModel.Set(this._rawData, "consumption_table", value); } } - public NewFloatingThresholdTotalAmountPrice() { } + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.ConsumptionTable) + { + item.Validate(); + } + _ = this.Prorate; + } + + public ThresholdTotalAmountConfig() { } + + public ThresholdTotalAmountConfig(ThresholdTotalAmountConfig thresholdTotalAmountConfig) + : base(thresholdTotalAmountConfig) { } + + public ThresholdTotalAmountConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingThresholdTotalAmountPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + ThresholdTotalAmountConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingThresholdTotalAmountPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static ThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ThresholdTotalAmountConfig(List consumptionTable) + : this() + { + this.ConsumptionTable = consumptionTable; + } +} + +class ThresholdTotalAmountConfigFromRaw : IFromRawJson +{ + /// + public ThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ThresholdTotalAmountConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single threshold +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ConsumptionTable : JsonModel +{ + /// + /// Quantity threshold + /// + public required string Threshold + { + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } + } + + /// + /// Total amount for this threshold + /// + public required string TotalAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "total_amount"); } + init { JsonModel.Set(this._rawData, "total_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Threshold; + _ = this.TotalAmount; + } + + public ConsumptionTable() { } + + public ConsumptionTable(ConsumptionTable consumptionTable) + : base(consumptionTable) { } + + public ConsumptionTable(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ConsumptionTable(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ConsumptionTableFromRaw : IFromRawJson +{ + /// + public ConsumptionTable FromRawUnchecked(IReadOnlyDictionary rawData) => + ConsumptionTable.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingThresholdTotalAmountPriceConversionRateConfigConverter))] +public record class NewFloatingThresholdTotalAmountPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingThresholdTotalAmountPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingThresholdTotalAmountPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingThresholdTotalAmountPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingThresholdTotalAmountPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingThresholdTotalAmountPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingThresholdTotalAmountPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingThresholdTotalAmountPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingThresholdTotalAmountPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingThresholdTotalAmountPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingThresholdTotalAmountPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingThresholdTotalAmountPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingThresholdTotalAmountPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingThresholdTotalAmountPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/Cadence.cs deleted file mode 100644 index 7b20e9c9..00000000 --- a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingThresholdTotalAmountPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index d3c074bb..00000000 --- a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingThresholdTotalAmountPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingThresholdTotalAmountPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index c1ecd231..00000000 --- a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingThresholdTotalAmountPriceProperties = Orb.Models.NewFloatingThresholdTotalAmountPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingThresholdTotalAmountPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingThresholdTotalAmountPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingThresholdTotalAmountPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ModelType.cs deleted file mode 100644 index 71e51b07..00000000 --- a/src/Orb/Models/NewFloatingThresholdTotalAmountPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingThresholdTotalAmountPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ThresholdTotalAmount = new("threshold_total_amount"); - - readonly string _value = value; - - public enum Value - { - ThresholdTotalAmount, - } - - public Value Known() => - _value switch - { - "threshold_total_amount" => Value.ThresholdTotalAmount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredBPSPrice.cs b/src/Orb/Models/NewFloatingTieredBPSPrice.cs deleted file mode 100644 index 73e1362b..00000000 --- a/src/Orb/Models/NewFloatingTieredBPSPrice.cs +++ /dev/null @@ -1,396 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingTieredBPSPriceProperties = Orb.Models.NewFloatingTieredBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingTieredBPSPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The cadence to bill for this price on. - /// - public required NewFloatingTieredBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 4217 currency string for which this price is billed in. - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewFloatingTieredBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredBPSConfig TieredBPSConfig - { - get - { - if (!this.Properties.TryGetValue("tiered_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_bps_config"); - } - set - { - this.Properties["tiered_bps_config"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewFloatingTieredBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Cadence.Validate(); - _ = this.Currency; - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - this.TieredBPSConfig.Validate(); - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - } - - public NewFloatingTieredBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingTieredBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewFloatingTieredBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingTieredBPSPriceProperties/Cadence.cs deleted file mode 100644 index 31745af5..00000000 --- a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 46b74588..00000000 --- a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingTieredBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 64059a74..00000000 --- a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingTieredBPSPriceProperties = Orb.Models.NewFloatingTieredBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingTieredBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingTieredBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ModelType.cs deleted file mode 100644 index bfada86b..00000000 --- a/src/Orb/Models/NewFloatingTieredBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredBPS = new("tiered_bps"); - - readonly string _value = value; - - public enum Value - { - TieredBPS, - } - - public Value Known() => - _value switch - { - "tiered_bps" => Value.TieredBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPackagePrice.cs b/src/Orb/Models/NewFloatingTieredPackagePrice.cs index 918f6468..d80a42cb 100644 --- a/src/Orb/Models/NewFloatingTieredPackagePrice.cs +++ b/src/Orb/Models/NewFloatingTieredPackagePrice.cs @@ -1,36 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingTieredPackagePriceProperties = Orb.Models.NewFloatingTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewFloatingTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +34,8 @@ public sealed record class NewFloatingTieredPackagePrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +43,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,39 +66,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredPackageConfig + /// + /// Configuration for tiered_package pricing + /// + public required TieredPackageConfig TieredPackageConfig { get { - if ( - !this.Properties.TryGetValue("tiered_package_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_config"); - } - set - { - this.Properties["tiered_package_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_config" ); } + init { JsonModel.Set(this._rawData, "tiered_package_config", value); } } /// @@ -133,60 +90,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -194,41 +125,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -238,21 +151,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +164,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +173,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +182,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +194,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,18 +207,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -362,10 +227,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredPackageConfig.Values) - { - _ = item; - } + this.TieredPackageConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -376,29 +238,563 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingTieredPackagePrice() { } + + public NewFloatingTieredPackagePrice( + NewFloatingTieredPackagePrice newFloatingTieredPackagePrice + ) + : base(newFloatingTieredPackagePrice) { } + + public NewFloatingTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingTieredPackagePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingTieredPackagePriceFromRaw : IFromRawJson +{ + /// + public NewFloatingTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingTieredPackagePriceCadenceConverter))] +public enum NewFloatingTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewFloatingTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingTieredPackagePriceCadence.Annual, + "semi_annual" => NewFloatingTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewFloatingTieredPackagePriceCadence.Monthly, + "quarterly" => NewFloatingTieredPackagePriceCadence.Quarterly, + "one_time" => NewFloatingTieredPackagePriceCadence.OneTime, + "custom" => NewFloatingTieredPackagePriceCadence.Custom, + _ => (NewFloatingTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingTieredPackagePriceCadence.Annual => "annual", + NewFloatingTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewFloatingTieredPackagePriceCadence.Monthly => "monthly", + NewFloatingTieredPackagePriceCadence.Quarterly => "quarterly", + NewFloatingTieredPackagePriceCadence.OneTime => "one_time", + NewFloatingTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingTieredPackagePriceModelTypeConverter))] +public enum NewFloatingTieredPackagePriceModelType +{ + TieredPackage, +} + +sealed class NewFloatingTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_package" => NewFloatingTieredPackagePriceModelType.TieredPackage, + _ => (NewFloatingTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingTieredPackagePriceModelType.TieredPackage => "tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredPackageConfig : JsonModel +{ + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. The tier bounds are defined + /// based on the total quantity rather than the number of packages, so they must + /// be multiples of the package size. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "tiers"); } + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewFloatingTieredPackagePrice() { } + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredPackageConfig() { } + + public TieredPackageConfig(TieredPackageConfig tieredPackageConfig) + : base(tieredPackageConfig) { } + + public TieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + TieredPackageConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static TieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageConfigFromRaw : IFromRawJson +{ + /// + public TieredPackageConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + TieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier with business logic +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public TieredPackageConfigTier() { } + + public TieredPackageConfigTier(TieredPackageConfigTier tieredPackageConfigTier) + : base(tieredPackageConfigTier) { } + + public TieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageConfigTierFromRaw : IFromRawJson +{ + /// + public TieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingTieredPackagePriceConversionRateConfigConverter))] +public record class NewFloatingTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index 10559d33..00000000 --- a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 7992c3f8..00000000 --- a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index a86edecf..00000000 --- a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingTieredPackagePriceProperties = Orb.Models.NewFloatingTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index 665735ee..00000000 --- a/src/Orb/Models/NewFloatingTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackage = new("tiered_package"); - - readonly string _value = value; - - public enum Value - { - TieredPackage, - } - - public Value Known() => - _value switch - { - "tiered_package" => Value.TieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPrice.cs b/src/Orb/Models/NewFloatingTieredPackageWithMinimumPrice.cs index b2707491..8fc7cea6 100644 --- a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPrice.cs +++ b/src/Orb/Models/NewFloatingTieredPackageWithMinimumPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingTieredPackageWithMinimumPriceProperties = Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingTieredPackageWithMinimumPrice, + NewFloatingTieredPackageWithMinimumPriceFromRaw + >) )] -public sealed record class NewFloatingTieredPackageWithMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewFloatingTieredPackageWithMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingTieredPackageWithMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,18 +36,8 @@ public sealed record class NewFloatingTieredPackageWithMinimumPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -59,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingTieredPackageWithMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -95,41 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredPackageWithMinimumConfig + /// + /// Configuration for tiered_package_with_minimum pricing + /// + public required TieredPackageWithMinimumConfig TieredPackageWithMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_package_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_with_minimum_config"); - } - set - { - this.Properties["tiered_package_with_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_with_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "tiered_package_with_minimum_config", value); } } /// @@ -137,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -198,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingTieredPackageWithMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingTieredPackageWithMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -242,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -325,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -366,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredPackageWithMinimumConfig.Values) - { - _ = item; - } + this.TieredPackageWithMinimumConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -380,31 +240,594 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingTieredPackageWithMinimumPrice() { } + + public NewFloatingTieredPackageWithMinimumPrice( + NewFloatingTieredPackageWithMinimumPrice newFloatingTieredPackageWithMinimumPrice + ) + : base(newFloatingTieredPackageWithMinimumPrice) { } + + public NewFloatingTieredPackageWithMinimumPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingTieredPackageWithMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingTieredPackageWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingTieredPackageWithMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewFloatingTieredPackageWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingTieredPackageWithMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingTieredPackageWithMinimumPriceCadenceConverter))] +public enum NewFloatingTieredPackageWithMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingTieredPackageWithMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingTieredPackageWithMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingTieredPackageWithMinimumPriceCadence.Annual, + "semi_annual" => NewFloatingTieredPackageWithMinimumPriceCadence.SemiAnnual, + "monthly" => NewFloatingTieredPackageWithMinimumPriceCadence.Monthly, + "quarterly" => NewFloatingTieredPackageWithMinimumPriceCadence.Quarterly, + "one_time" => NewFloatingTieredPackageWithMinimumPriceCadence.OneTime, + "custom" => NewFloatingTieredPackageWithMinimumPriceCadence.Custom, + _ => (NewFloatingTieredPackageWithMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPackageWithMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingTieredPackageWithMinimumPriceCadence.Annual => "annual", + NewFloatingTieredPackageWithMinimumPriceCadence.SemiAnnual => "semi_annual", + NewFloatingTieredPackageWithMinimumPriceCadence.Monthly => "monthly", + NewFloatingTieredPackageWithMinimumPriceCadence.Quarterly => "quarterly", + NewFloatingTieredPackageWithMinimumPriceCadence.OneTime => "one_time", + NewFloatingTieredPackageWithMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingTieredPackageWithMinimumPriceModelTypeConverter))] +public enum NewFloatingTieredPackageWithMinimumPriceModelType +{ + TieredPackageWithMinimum, +} + +sealed class NewFloatingTieredPackageWithMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingTieredPackageWithMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_package_with_minimum" => + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + _ => (NewFloatingTieredPackageWithMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPackageWithMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum => + "tiered_package_with_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageWithMinimumConfig, + TieredPackageWithMinimumConfigFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumConfig : JsonModel +{ + /// + /// Package size + /// + public required double PackageSize + { + get { return JsonModel.GetNotNullStruct(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); } + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewFloatingTieredPackageWithMinimumPrice() { } + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredPackageWithMinimumConfig() { } + + public TieredPackageWithMinimumConfig( + TieredPackageWithMinimumConfig tieredPackageWithMinimumConfig + ) + : base(tieredPackageWithMinimumConfig) { } + + public TieredPackageWithMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingTieredPackageWithMinimumPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + TieredPackageWithMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumConfigFromRaw : IFromRawJson +{ + /// + public TieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageWithMinimumConfigTier, + TieredPackageWithMinimumConfigTierFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public TieredPackageWithMinimumConfigTier() { } + + public TieredPackageWithMinimumConfigTier( + TieredPackageWithMinimumConfigTier tieredPackageWithMinimumConfigTier + ) + : base(tieredPackageWithMinimumConfigTier) { } + + public TieredPackageWithMinimumConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageWithMinimumConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingTieredPackageWithMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static TieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumConfigTierFromRaw : IFromRawJson +{ + /// + public TieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageWithMinimumConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingTieredPackageWithMinimumPriceConversionRateConfigConverter))] +public record class NewFloatingTieredPackageWithMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingTieredPackageWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredPackageWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredPackageWithMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPackageWithMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPackageWithMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingTieredPackageWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingTieredPackageWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPackageWithMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingTieredPackageWithMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingTieredPackageWithMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingTieredPackageWithMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingTieredPackageWithMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPackageWithMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/Cadence.cs deleted file mode 100644 index a905426f..00000000 --- a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index f2198136..00000000 --- a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index a872952f..00000000 --- a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingTieredPackageWithMinimumPriceProperties = Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingTieredPackageWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingTieredPackageWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ModelType.cs deleted file mode 100644 index fdf30cc2..00000000 --- a/src/Orb/Models/NewFloatingTieredPackageWithMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredPackageWithMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackageWithMinimum = new("tiered_package_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredPackageWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_package_with_minimum" => Value.TieredPackageWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPrice.cs b/src/Orb/Models/NewFloatingTieredPrice.cs index cd28d77d..a0e8774e 100644 --- a/src/Orb/Models/NewFloatingTieredPrice.cs +++ b/src/Orb/Models/NewFloatingTieredPrice.cs @@ -1,36 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingTieredPriceProperties = Orb.Models.NewFloatingTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingTieredPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewFloatingTieredPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingTieredPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +32,8 @@ public sealed record class NewFloatingTieredPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +41,23 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingTieredPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,31 +65,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// + /// Configuration for tiered pricing + /// public required TieredConfig TieredConfig { - get - { - if (!this.Properties.TryGetValue("tiered_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_config"); - } - set { this.Properties["tiered_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "tiered_config"); } + init { JsonModel.Set(this._rawData, "tiered_config", value); } } /// @@ -125,60 +83,34 @@ public required TieredConfig TieredConfig /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,41 +118,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingTieredPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingTieredPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -230,21 +144,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +157,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +166,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,19 +175,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -313,21 +187,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,18 +200,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,29 +231,420 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingTieredPrice() { } + public NewFloatingTieredPrice(NewFloatingTieredPrice newFloatingTieredPrice) + : base(newFloatingTieredPrice) { } + + public NewFloatingTieredPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingTieredPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingTieredPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingTieredPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingTieredPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingTieredPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingTieredPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingTieredPriceCadenceConverter))] +public enum NewFloatingTieredPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingTieredPriceCadenceConverter : JsonConverter +{ + public override NewFloatingTieredPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingTieredPriceCadence.Annual, + "semi_annual" => NewFloatingTieredPriceCadence.SemiAnnual, + "monthly" => NewFloatingTieredPriceCadence.Monthly, + "quarterly" => NewFloatingTieredPriceCadence.Quarterly, + "one_time" => NewFloatingTieredPriceCadence.OneTime, + "custom" => NewFloatingTieredPriceCadence.Custom, + _ => (NewFloatingTieredPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingTieredPriceCadence.Annual => "annual", + NewFloatingTieredPriceCadence.SemiAnnual => "semi_annual", + NewFloatingTieredPriceCadence.Monthly => "monthly", + NewFloatingTieredPriceCadence.Quarterly => "quarterly", + NewFloatingTieredPriceCadence.OneTime => "one_time", + NewFloatingTieredPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingTieredPriceModelTypeConverter))] +public enum NewFloatingTieredPriceModelType +{ + Tiered, +} + +sealed class NewFloatingTieredPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingTieredPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered" => NewFloatingTieredPriceModelType.Tiered, + _ => (NewFloatingTieredPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingTieredPriceModelType.Tiered => "tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingTieredPriceConversionRateConfigConverter))] +public record class NewFloatingTieredPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingTieredPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingTieredPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingTieredPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingTieredPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingTieredPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingTieredPriceProperties/Cadence.cs deleted file mode 100644 index 2571caea..00000000 --- a/src/Orb/Models/NewFloatingTieredPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingTieredPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index b3a12991..00000000 --- a/src/Orb/Models/NewFloatingTieredPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingTieredPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingTieredPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingTieredPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index fb36dd24..00000000 --- a/src/Orb/Models/NewFloatingTieredPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingTieredPriceProperties = Orb.Models.NewFloatingTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingTieredPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingTieredPriceProperties/ModelType.cs deleted file mode 100644 index dda077e6..00000000 --- a/src/Orb/Models/NewFloatingTieredPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Tiered = new("tiered"); - - readonly string _value = value; - - public enum Value - { - Tiered, - } - - public Value Known() => - _value switch - { - "tiered" => Value.Tiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredWithMinimumPrice.cs b/src/Orb/Models/NewFloatingTieredWithMinimumPrice.cs index 5ede2bf0..bee2caba 100644 --- a/src/Orb/Models/NewFloatingTieredWithMinimumPrice.cs +++ b/src/Orb/Models/NewFloatingTieredWithMinimumPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingTieredWithMinimumPriceProperties = Orb.Models.NewFloatingTieredWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingTieredWithMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingTieredWithMinimumPrice, + NewFloatingTieredWithMinimumPriceFromRaw + >) +)] +public sealed record class NewFloatingTieredWithMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingTieredWithMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingTieredWithMinimumPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingTieredWithMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,42 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredWithMinimumConfig + /// + /// Configuration for tiered_with_minimum pricing + /// + public required TieredWithMinimumConfig TieredWithMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_minimum_config"); - } - set - { - this.Properties["tiered_with_minimum_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_minimum_config" ); } + init { JsonModel.Set(this._rawData, "tiered_with_minimum_config", value); } } /// @@ -136,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -197,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingTieredWithMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingTieredWithMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -241,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -324,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredWithMinimumConfig.Values) - { - _ = item; - } + this.TieredWithMinimumConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -379,29 +240,611 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingTieredWithMinimumPrice() { } + + public NewFloatingTieredWithMinimumPrice( + NewFloatingTieredWithMinimumPrice newFloatingTieredWithMinimumPrice + ) + : base(newFloatingTieredWithMinimumPrice) { } + + public NewFloatingTieredWithMinimumPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingTieredWithMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingTieredWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingTieredWithMinimumPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingTieredWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingTieredWithMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingTieredWithMinimumPriceCadenceConverter))] +public enum NewFloatingTieredWithMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingTieredWithMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingTieredWithMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingTieredWithMinimumPriceCadence.Annual, + "semi_annual" => NewFloatingTieredWithMinimumPriceCadence.SemiAnnual, + "monthly" => NewFloatingTieredWithMinimumPriceCadence.Monthly, + "quarterly" => NewFloatingTieredWithMinimumPriceCadence.Quarterly, + "one_time" => NewFloatingTieredWithMinimumPriceCadence.OneTime, + "custom" => NewFloatingTieredWithMinimumPriceCadence.Custom, + _ => (NewFloatingTieredWithMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredWithMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; + NewFloatingTieredWithMinimumPriceCadence.Annual => "annual", + NewFloatingTieredWithMinimumPriceCadence.SemiAnnual => "semi_annual", + NewFloatingTieredWithMinimumPriceCadence.Monthly => "monthly", + NewFloatingTieredWithMinimumPriceCadence.Quarterly => "quarterly", + NewFloatingTieredWithMinimumPriceCadence.OneTime => "one_time", + NewFloatingTieredWithMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingTieredWithMinimumPriceModelTypeConverter))] +public enum NewFloatingTieredWithMinimumPriceModelType +{ + TieredWithMinimum, +} + +sealed class NewFloatingTieredWithMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingTieredWithMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_with_minimum" => NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum, + _ => (NewFloatingTieredWithMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredWithMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingTieredWithMinimumPriceModelType.TieredWithMinimum => + "tiered_with_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_minimum pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredWithMinimumConfig : JsonModel +{ + /// + /// Tiered pricing with a minimum amount dependent on the volume tier. Tiers + /// are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// If true, tiers with an accrued amount of 0 will not be included in the rating. + /// + public bool? HideZeroAmountTiers + { + get { return JsonModel.GetNullableStruct(this.RawData, "hide_zero_amount_tiers"); } + init + { + if (value == null) + { + return; } + + JsonModel.Set(this._rawData, "hide_zero_amount_tiers", value); } } - public NewFloatingTieredWithMinimumPrice() { } + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorate", value); + } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.HideZeroAmountTiers; + _ = this.Prorate; + } + + public TieredWithMinimumConfig() { } + + public TieredWithMinimumConfig(TieredWithMinimumConfig tieredWithMinimumConfig) + : base(tieredWithMinimumConfig) { } + + public TieredWithMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingTieredWithMinimumPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + TieredWithMinimumConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingTieredWithMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static TieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithMinimumConfig(List tiers) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithMinimumConfigFromRaw : IFromRawJson +{ + /// + public TieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class TieredWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithMinimumConfigTier() { } + + public TieredWithMinimumConfigTier(TieredWithMinimumConfigTier tieredWithMinimumConfigTier) + : base(tieredWithMinimumConfigTier) { } + + public TieredWithMinimumConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithMinimumConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithMinimumConfigTierFromRaw : IFromRawJson +{ + /// + public TieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithMinimumConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingTieredWithMinimumPriceConversionRateConfigConverter))] +public record class NewFloatingTieredWithMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingTieredWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredWithMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredWithMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredWithMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingTieredWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingTieredWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredWithMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingTieredWithMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingTieredWithMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingTieredWithMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingTieredWithMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredWithMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/Cadence.cs deleted file mode 100644 index e89df043..00000000 --- a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredWithMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 0610b148..00000000 --- a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingTieredWithMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredWithMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 1c0cddb4..00000000 --- a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingTieredWithMinimumPriceProperties = Orb.Models.NewFloatingTieredWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredWithMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingTieredWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingTieredWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ModelType.cs deleted file mode 100644 index e305e789..00000000 --- a/src/Orb/Models/NewFloatingTieredWithMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredWithMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithMinimum = new("tiered_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_with_minimum" => Value.TieredWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredWithProrationPrice.cs b/src/Orb/Models/NewFloatingTieredWithProrationPrice.cs index ff63eff2..45780a58 100644 --- a/src/Orb/Models/NewFloatingTieredWithProrationPrice.cs +++ b/src/Orb/Models/NewFloatingTieredWithProrationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingTieredWithProrationPriceProperties = Orb.Models.NewFloatingTieredWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingTieredWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingTieredWithProrationPrice, + NewFloatingTieredWithProrationPriceFromRaw + >) +)] +public sealed record class NewFloatingTieredWithProrationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingTieredWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingTieredWithProrationPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingTieredWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,41 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredWithProrationConfig + /// + /// Configuration for tiered_with_proration pricing + /// + public required TieredWithProrationConfig TieredWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_proration_config"); - } - set - { - this.Properties["tiered_with_proration_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } } /// @@ -135,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -196,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingTieredWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingTieredWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -240,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -262,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -280,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -300,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -323,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -345,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -364,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredWithProrationConfig.Values) - { - _ = item; - } + this.TieredWithProrationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -378,29 +240,570 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + } + + public NewFloatingTieredWithProrationPrice() { } + + public NewFloatingTieredWithProrationPrice( + NewFloatingTieredWithProrationPrice newFloatingTieredWithProrationPrice + ) + : base(newFloatingTieredWithProrationPrice) { } + + public NewFloatingTieredWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewFloatingTieredWithProrationPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewFloatingTieredWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingTieredWithProrationPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingTieredWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingTieredWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingTieredWithProrationPriceCadenceConverter))] +public enum NewFloatingTieredWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingTieredWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingTieredWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewFloatingTieredWithProrationPriceCadence.Annual, + "semi_annual" => NewFloatingTieredWithProrationPriceCadence.SemiAnnual, + "monthly" => NewFloatingTieredWithProrationPriceCadence.Monthly, + "quarterly" => NewFloatingTieredWithProrationPriceCadence.Quarterly, + "one_time" => NewFloatingTieredWithProrationPriceCadence.OneTime, + "custom" => NewFloatingTieredWithProrationPriceCadence.Custom, + _ => (NewFloatingTieredWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewFloatingTieredWithProrationPriceCadence.Annual => "annual", + NewFloatingTieredWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewFloatingTieredWithProrationPriceCadence.Monthly => "monthly", + NewFloatingTieredWithProrationPriceCadence.Quarterly => "quarterly", + NewFloatingTieredWithProrationPriceCadence.OneTime => "one_time", + NewFloatingTieredWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingTieredWithProrationPriceModelTypeConverter))] +public enum NewFloatingTieredWithProrationPriceModelType +{ + TieredWithProration, +} + +sealed class NewFloatingTieredWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingTieredWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_with_proration" => + NewFloatingTieredWithProrationPriceModelType.TieredWithProration, + _ => (NewFloatingTieredWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingTieredWithProrationPriceModelType.TieredWithProration => + "tiered_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class TieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); } + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewFloatingTieredWithProrationPrice() { } + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredWithProrationConfig() { } + + public TieredWithProrationConfig(TieredWithProrationConfig tieredWithProrationConfig) + : base(tieredWithProrationConfig) { } + + public TieredWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingTieredWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + TieredWithProrationConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewFloatingTieredWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithProrationConfig(List tiers) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithProrationConfigFromRaw : IFromRawJson +{ + /// + public TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class TieredWithProrationConfigTier : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithProrationConfigTier() { } + + public TieredWithProrationConfigTier( + TieredWithProrationConfigTier tieredWithProrationConfigTier + ) + : base(tieredWithProrationConfigTier) { } + + public TieredWithProrationConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationConfigTierFromRaw : IFromRawJson +{ + /// + public TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingTieredWithProrationPriceConversionRateConfigConverter))] +public record class NewFloatingTieredWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingTieredWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingTieredWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingTieredWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingTieredWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingTieredWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingTieredWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingTieredWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingTieredWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingTieredWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingTieredWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index d7756633..00000000 --- a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 71fb7dc9..00000000 --- a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingTieredWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index ee23fe1a..00000000 --- a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingTieredWithProrationPriceProperties = Orb.Models.NewFloatingTieredWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingTieredWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingTieredWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingTieredWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index b7bdc9ef..00000000 --- a/src/Orb/Models/NewFloatingTieredWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingTieredWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithProration = new("tiered_with_proration"); - - readonly string _value = value; - - public enum Value - { - TieredWithProration, - } - - public Value Known() => - _value switch - { - "tiered_with_proration" => Value.TieredWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingUnitPrice.cs b/src/Orb/Models/NewFloatingUnitPrice.cs index 23fa04ec..77a3c35d 100644 --- a/src/Orb/Models/NewFloatingUnitPrice.cs +++ b/src/Orb/Models/NewFloatingUnitPrice.cs @@ -1,36 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingUnitPriceProperties = Orb.Models.NewFloatingUnitPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingUnitPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewFloatingUnitPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingUnitPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +32,8 @@ public sealed record class NewFloatingUnitPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +41,23 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingUnitPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,31 +65,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// + /// Configuration for unit pricing + /// public required UnitConfig UnitConfig { - get - { - if (!this.Properties.TryGetValue("unit_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_config"); - } - set { this.Properties["unit_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_config"); } + init { JsonModel.Set(this._rawData, "unit_config", value); } } /// @@ -125,60 +83,34 @@ public required UnitConfig UnitConfig /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,41 +118,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingUnitPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingUnitPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -230,21 +144,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +157,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +166,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,19 +175,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -313,21 +187,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,18 +200,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,29 +231,419 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingUnitPrice() { } + public NewFloatingUnitPrice(NewFloatingUnitPrice newFloatingUnitPrice) + : base(newFloatingUnitPrice) { } + + public NewFloatingUnitPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingUnitPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingUnitPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingUnitPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingUnitPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingUnitPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingUnitPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingUnitPriceCadenceConverter))] +public enum NewFloatingUnitPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingUnitPriceCadenceConverter : JsonConverter +{ + public override NewFloatingUnitPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingUnitPriceCadence.Annual, + "semi_annual" => NewFloatingUnitPriceCadence.SemiAnnual, + "monthly" => NewFloatingUnitPriceCadence.Monthly, + "quarterly" => NewFloatingUnitPriceCadence.Quarterly, + "one_time" => NewFloatingUnitPriceCadence.OneTime, + "custom" => NewFloatingUnitPriceCadence.Custom, + _ => (NewFloatingUnitPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingUnitPriceCadence.Annual => "annual", + NewFloatingUnitPriceCadence.SemiAnnual => "semi_annual", + NewFloatingUnitPriceCadence.Monthly => "monthly", + NewFloatingUnitPriceCadence.Quarterly => "quarterly", + NewFloatingUnitPriceCadence.OneTime => "one_time", + NewFloatingUnitPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingUnitPriceModelTypeConverter))] +public enum NewFloatingUnitPriceModelType +{ + Unit, +} + +sealed class NewFloatingUnitPriceModelTypeConverter : JsonConverter +{ + public override NewFloatingUnitPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit" => NewFloatingUnitPriceModelType.Unit, + _ => (NewFloatingUnitPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingUnitPriceModelType.Unit => "unit", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewFloatingUnitPriceConversionRateConfigConverter))] +public record class NewFloatingUnitPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingUnitPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingUnitPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingUnitPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingUnitPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingUnitPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingUnitPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingUnitPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingUnitPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingUnitPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingUnitPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingUnitPriceProperties/Cadence.cs deleted file mode 100644 index 7e0b1f52..00000000 --- a/src/Orb/Models/NewFloatingUnitPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingUnitPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingUnitPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingUnitPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index a07a6146..00000000 --- a/src/Orb/Models/NewFloatingUnitPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingUnitPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingUnitPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingUnitPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingUnitPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 7aa62a48..00000000 --- a/src/Orb/Models/NewFloatingUnitPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingUnitPriceProperties = Orb.Models.NewFloatingUnitPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingUnitPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingUnitPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingUnitPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingUnitPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingUnitPriceProperties/ModelType.cs deleted file mode 100644 index d2c8fa4f..00000000 --- a/src/Orb/Models/NewFloatingUnitPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingUnitPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Unit = new("unit"); - - readonly string _value = value; - - public enum Value - { - Unit, - } - - public Value Known() => - _value switch - { - "unit" => Value.Unit, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingUnitWithPercentPrice.cs b/src/Orb/Models/NewFloatingUnitWithPercentPrice.cs index d10f9069..79eef723 100644 --- a/src/Orb/Models/NewFloatingUnitWithPercentPrice.cs +++ b/src/Orb/Models/NewFloatingUnitWithPercentPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingUnitWithPercentPriceProperties = Orb.Models.NewFloatingUnitWithPercentPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingUnitWithPercentPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingUnitWithPercentPrice, + NewFloatingUnitWithPercentPriceFromRaw + >) +)] +public sealed record class NewFloatingUnitWithPercentPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingUnitWithPercentPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingUnitWithPercentPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingUnitWithPercentPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,42 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary UnitWithPercentConfig + /// + /// Configuration for unit_with_percent pricing + /// + public required UnitWithPercentConfig UnitWithPercentConfig { get { - if ( - !this.Properties.TryGetValue( - "unit_with_percent_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_percent_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_percent_config"); - } - set - { - this.Properties["unit_with_percent_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_percent_config" ); } + init { JsonModel.Set(this._rawData, "unit_with_percent_config", value); } } /// @@ -136,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -197,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingUnitWithPercentPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingUnitWithPercentPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -241,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -324,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.UnitWithPercentConfig.Values) - { - _ = item; - } + this.UnitWithPercentConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -379,29 +240,489 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingUnitWithPercentPrice() { } + public NewFloatingUnitWithPercentPrice( + NewFloatingUnitWithPercentPrice newFloatingUnitWithPercentPrice + ) + : base(newFloatingUnitWithPercentPrice) { } + + public NewFloatingUnitWithPercentPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingUnitWithPercentPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingUnitWithPercentPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingUnitWithPercentPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingUnitWithPercentPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingUnitWithPercentPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingUnitWithPercentPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingUnitWithPercentPriceCadenceConverter))] +public enum NewFloatingUnitWithPercentPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingUnitWithPercentPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingUnitWithPercentPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingUnitWithPercentPriceCadence.Annual, + "semi_annual" => NewFloatingUnitWithPercentPriceCadence.SemiAnnual, + "monthly" => NewFloatingUnitWithPercentPriceCadence.Monthly, + "quarterly" => NewFloatingUnitWithPercentPriceCadence.Quarterly, + "one_time" => NewFloatingUnitWithPercentPriceCadence.OneTime, + "custom" => NewFloatingUnitWithPercentPriceCadence.Custom, + _ => (NewFloatingUnitWithPercentPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitWithPercentPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingUnitWithPercentPriceCadence.Annual => "annual", + NewFloatingUnitWithPercentPriceCadence.SemiAnnual => "semi_annual", + NewFloatingUnitWithPercentPriceCadence.Monthly => "monthly", + NewFloatingUnitWithPercentPriceCadence.Quarterly => "quarterly", + NewFloatingUnitWithPercentPriceCadence.OneTime => "one_time", + NewFloatingUnitWithPercentPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingUnitWithPercentPriceModelTypeConverter))] +public enum NewFloatingUnitWithPercentPriceModelType +{ + UnitWithPercent, +} + +sealed class NewFloatingUnitWithPercentPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingUnitWithPercentPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit_with_percent" => NewFloatingUnitWithPercentPriceModelType.UnitWithPercent, + _ => (NewFloatingUnitWithPercentPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitWithPercentPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingUnitWithPercentPriceModelType.UnitWithPercent => "unit_with_percent", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_percent pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UnitWithPercentConfig : JsonModel +{ + /// + /// What percent, out of 100, of the calculated total to charge + /// + public required string Percent + { + get { return JsonModel.GetNotNullClass(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + _ = this.UnitAmount; + } + + public UnitWithPercentConfig() { } + + public UnitWithPercentConfig(UnitWithPercentConfig unitWithPercentConfig) + : base(unitWithPercentConfig) { } + + public UnitWithPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithPercentConfigFromRaw : IFromRawJson +{ + /// + public UnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UnitWithPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingUnitWithPercentPriceConversionRateConfigConverter))] +public record class NewFloatingUnitWithPercentPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingUnitWithPercentPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingUnitWithPercentPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingUnitWithPercentPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitWithPercentPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitWithPercentPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingUnitWithPercentPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingUnitWithPercentPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitWithPercentPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingUnitWithPercentPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingUnitWithPercentPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingUnitWithPercentPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingUnitWithPercentPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitWithPercentPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/Cadence.cs deleted file mode 100644 index 34937ece..00000000 --- a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingUnitWithPercentPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 922cfb2a..00000000 --- a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingUnitWithPercentPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingUnitWithPercentPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f06e3f32..00000000 --- a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingUnitWithPercentPriceProperties = Orb.Models.NewFloatingUnitWithPercentPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingUnitWithPercentPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingUnitWithPercentPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingUnitWithPercentPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ModelType.cs deleted file mode 100644 index 5ac1cba7..00000000 --- a/src/Orb/Models/NewFloatingUnitWithPercentPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingUnitWithPercentPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithPercent = new("unit_with_percent"); - - readonly string _value = value; - - public enum Value - { - UnitWithPercent, - } - - public Value Known() => - _value switch - { - "unit_with_percent" => Value.UnitWithPercent, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingUnitWithProrationPrice.cs b/src/Orb/Models/NewFloatingUnitWithProrationPrice.cs index b22ebb5f..b9c2b2c5 100644 --- a/src/Orb/Models/NewFloatingUnitWithProrationPrice.cs +++ b/src/Orb/Models/NewFloatingUnitWithProrationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewFloatingUnitWithProrationPriceProperties = Orb.Models.NewFloatingUnitWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewFloatingUnitWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewFloatingUnitWithProrationPrice, + NewFloatingUnitWithProrationPriceFromRaw + >) +)] +public sealed record class NewFloatingUnitWithProrationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewFloatingUnitWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,18 +36,8 @@ public sealed record class NewFloatingUnitWithProrationPrice /// public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -57,35 +45,22 @@ public required string Currency /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewFloatingUnitWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -93,42 +68,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary UnitWithProrationConfig + /// + /// Configuration for unit_with_proration pricing + /// + public required UnitWithProrationConfig UnitWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "unit_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_proration_config"); - } - set - { - this.Properties["unit_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_proration_config" ); } + init { JsonModel.Set(this._rawData, "unit_with_proration_config", value); } } /// @@ -136,60 +92,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -197,41 +127,23 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewFloatingUnitWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewFloatingUnitWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// @@ -241,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -324,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,18 +209,19 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -365,10 +229,7 @@ public override void Validate() _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.UnitWithProrationConfig.Values) - { - _ = item; - } + this.UnitWithProrationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -379,29 +240,487 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; } public NewFloatingUnitWithProrationPrice() { } + public NewFloatingUnitWithProrationPrice( + NewFloatingUnitWithProrationPrice newFloatingUnitWithProrationPrice + ) + : base(newFloatingUnitWithProrationPrice) { } + + public NewFloatingUnitWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewFloatingUnitWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewFloatingUnitWithProrationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewFloatingUnitWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewFloatingUnitWithProrationPriceFromRaw : IFromRawJson +{ + /// + public NewFloatingUnitWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewFloatingUnitWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewFloatingUnitWithProrationPriceCadenceConverter))] +public enum NewFloatingUnitWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewFloatingUnitWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewFloatingUnitWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewFloatingUnitWithProrationPriceCadence.Annual, + "semi_annual" => NewFloatingUnitWithProrationPriceCadence.SemiAnnual, + "monthly" => NewFloatingUnitWithProrationPriceCadence.Monthly, + "quarterly" => NewFloatingUnitWithProrationPriceCadence.Quarterly, + "one_time" => NewFloatingUnitWithProrationPriceCadence.OneTime, + "custom" => NewFloatingUnitWithProrationPriceCadence.Custom, + _ => (NewFloatingUnitWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingUnitWithProrationPriceCadence.Annual => "annual", + NewFloatingUnitWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewFloatingUnitWithProrationPriceCadence.Monthly => "monthly", + NewFloatingUnitWithProrationPriceCadence.Quarterly => "quarterly", + NewFloatingUnitWithProrationPriceCadence.OneTime => "one_time", + NewFloatingUnitWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewFloatingUnitWithProrationPriceModelTypeConverter))] +public enum NewFloatingUnitWithProrationPriceModelType +{ + UnitWithProration, +} + +sealed class NewFloatingUnitWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewFloatingUnitWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit_with_proration" => NewFloatingUnitWithProrationPriceModelType.UnitWithProration, + _ => (NewFloatingUnitWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewFloatingUnitWithProrationPriceModelType.UnitWithProration => + "unit_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_proration pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UnitWithProrationConfig : JsonModel +{ + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + } + + public UnitWithProrationConfig() { } + + public UnitWithProrationConfig(UnitWithProrationConfig unitWithProrationConfig) + : base(unitWithProrationConfig) { } + + public UnitWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public UnitWithProrationConfig(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class UnitWithProrationConfigFromRaw : IFromRawJson +{ + /// + public UnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UnitWithProrationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewFloatingUnitWithProrationPriceConversionRateConfigConverter))] +public record class NewFloatingUnitWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewFloatingUnitWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingUnitWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewFloatingUnitWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewFloatingUnitWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewFloatingUnitWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewFloatingUnitWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewFloatingUnitWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewFloatingUnitWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewFloatingUnitWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewFloatingUnitWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewFloatingUnitWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index 3c35fd3d..00000000 --- a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingUnitWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index a46202de..00000000 --- a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewFloatingUnitWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingUnitWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 1176ed0e..00000000 --- a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewFloatingUnitWithProrationPriceProperties = Orb.Models.NewFloatingUnitWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewFloatingUnitWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewFloatingUnitWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewFloatingUnitWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index 7f8912d1..00000000 --- a/src/Orb/Models/NewFloatingUnitWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewFloatingUnitWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithProration = new("unit_with_proration"); - - readonly string _value = value; - - public enum Value - { - UnitWithProration, - } - - public Value Known() => - _value switch - { - "unit_with_proration" => Value.UnitWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewMaximum.cs b/src/Orb/Models/NewMaximum.cs index 6a614172..ce02f73f 100644 --- a/src/Orb/Models/NewMaximum.cs +++ b/src/Orb/Models/NewMaximum.cs @@ -1,99 +1,72 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewMaximumProperties = Orb.Models.NewMaximumProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewMaximum : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewMaximum : JsonModel { - public required NewMaximumProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_type" + ); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } public required string MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("maximum_amount"); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// /// If set, the adjustment will apply to every price on the subscription. /// - public NewMaximumProperties::AppliesToAll? AppliesToAll + public ApiEnum? AppliesToAll { get { - if (!this.Properties.TryGetValue("applies_to_all", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_all" + ); } - set { this.Properties["applies_to_all"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applies_to_all", value); } } /// /// The set of item IDs to which this adjustment applies. /// - public Generic::List? AppliesToItemIDs + public IReadOnlyList? AppliesToItemIDs { get { - if (!this.Properties.TryGetValue("applies_to_item_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_item_ids"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_item_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_item_ids", value); } } /// /// The set of price IDs to which this adjustment applies. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// @@ -101,78 +74,60 @@ public required string MaximumAmount /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// A list of filters that determine which prices this adjustment will apply to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { - get - { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass>(this.RawData, "filters"); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// When false, this adjustment will be applied to a single price. Otherwise, it - /// will be applied at the invoice level, possibly to multiple prices. + /// When false, this adjustment will be applied to a single price. Otherwise, + /// it will be applied at the invoice level, possibly to multiple prices. /// public bool? IsInvoiceLevel { - get + get { return JsonModel.GetNullableStruct(this.RawData, "is_invoice_level"); } + init { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// /// If set, only prices of the specified type will have the adjustment applied. /// - public NewMaximumProperties::PriceType? PriceType + public ApiEnum? PriceType { get { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawData, + "price_type" + ); } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_type", value); } } + /// public override void Validate() { this.AdjustmentType.Validate(); _ = this.MaximumAmount; this.AppliesToAll?.Validate(); - foreach (var item in this.AppliesToItemIDs ?? []) - { - _ = item; - } - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToItemIDs; + _ = this.AppliesToPriceIDs; _ = this.Currency; foreach (var item in this.Filters ?? []) { @@ -184,18 +139,360 @@ public override void Validate() public NewMaximum() { } + public NewMaximum(NewMaximum newMaximum) + : base(newMaximum) { } + + public NewMaximum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewMaximum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewMaximum FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewMaximumFromRaw : IFromRawJson +{ + /// + public NewMaximum FromRawUnchecked(IReadOnlyDictionary rawData) => + NewMaximum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewMaximumAdjustmentTypeConverter))] +public enum NewMaximumAdjustmentType +{ + Maximum, +} + +sealed class NewMaximumAdjustmentTypeConverter : JsonConverter +{ + public override NewMaximumAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "maximum" => NewMaximumAdjustmentType.Maximum, + _ => (NewMaximumAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMaximumAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMaximumAdjustmentType.Maximum => "maximum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, the adjustment will apply to every price on the subscription. +/// +[JsonConverter(typeof(NewMaximumAppliesToAllConverter))] +public enum NewMaximumAppliesToAll +{ + True, +} + +sealed class NewMaximumAppliesToAllConverter : JsonConverter +{ + public override NewMaximumAppliesToAll Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + true => NewMaximumAppliesToAll.True, + _ => (NewMaximumAppliesToAll)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMaximumAppliesToAll value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMaximumAppliesToAll.True => true, + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewMaximumFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public NewMaximumFilter() { } + + public NewMaximumFilter(NewMaximumFilter newMaximumFilter) + : base(newMaximumFilter) { } + + public NewMaximumFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewMaximum(Generic::Dictionary properties) + [SetsRequiredMembers] + NewMaximumFilter(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewMaximum FromRawUnchecked( - Generic::Dictionary properties + /// + public static NewMaximumFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewMaximumFilterFromRaw : IFromRawJson +{ + /// + public NewMaximumFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + NewMaximumFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(NewMaximumFilterFieldConverter))] +public enum NewMaximumFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class NewMaximumFilterFieldConverter : JsonConverter +{ + public override NewMaximumFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => NewMaximumFilterField.PriceID, + "item_id" => NewMaximumFilterField.ItemID, + "price_type" => NewMaximumFilterField.PriceType, + "currency" => NewMaximumFilterField.Currency, + "pricing_unit_id" => NewMaximumFilterField.PricingUnitID, + _ => (NewMaximumFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMaximumFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMaximumFilterField.PriceID => "price_id", + NewMaximumFilterField.ItemID => "item_id", + NewMaximumFilterField.PriceType => "price_type", + NewMaximumFilterField.Currency => "currency", + NewMaximumFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(NewMaximumFilterOperatorConverter))] +public enum NewMaximumFilterOperator +{ + Includes, + Excludes, +} + +sealed class NewMaximumFilterOperatorConverter : JsonConverter +{ + public override NewMaximumFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => NewMaximumFilterOperator.Includes, + "excludes" => NewMaximumFilterOperator.Excludes, + _ => (NewMaximumFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMaximumFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMaximumFilterOperator.Includes => "includes", + NewMaximumFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, only prices of the specified type will have the adjustment applied. +/// +[JsonConverter(typeof(NewMaximumPriceTypeConverter))] +public enum NewMaximumPriceType +{ + Usage, + FixedInAdvance, + FixedInArrears, + Fixed, + InArrears, +} + +sealed class NewMaximumPriceTypeConverter : JsonConverter +{ + public override NewMaximumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => NewMaximumPriceType.Usage, + "fixed_in_advance" => NewMaximumPriceType.FixedInAdvance, + "fixed_in_arrears" => NewMaximumPriceType.FixedInArrears, + "fixed" => NewMaximumPriceType.Fixed, + "in_arrears" => NewMaximumPriceType.InArrears, + _ => (NewMaximumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMaximumPriceType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewMaximumPriceType.Usage => "usage", + NewMaximumPriceType.FixedInAdvance => "fixed_in_advance", + NewMaximumPriceType.FixedInArrears => "fixed_in_arrears", + NewMaximumPriceType.Fixed => "fixed", + NewMaximumPriceType.InArrears => "in_arrears", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewMaximumProperties/AdjustmentType.cs b/src/Orb/Models/NewMaximumProperties/AdjustmentType.cs deleted file mode 100644 index 5f2beaa0..00000000 --- a/src/Orb/Models/NewMaximumProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewMaximumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType Maximum = new("maximum"); - - readonly string _value = value; - - public enum Value - { - Maximum, - } - - public Value Known() => - _value switch - { - "maximum" => Value.Maximum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewMaximumProperties/AppliesToAll.cs b/src/Orb/Models/NewMaximumProperties/AppliesToAll.cs deleted file mode 100644 index 2754e030..00000000 --- a/src/Orb/Models/NewMaximumProperties/AppliesToAll.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewMaximumProperties; - -/// -/// If set, the adjustment will apply to every price on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AppliesToAll(bool value) : Orb::IEnum -{ - public static readonly AppliesToAll True = new(true); - - readonly bool _value = value; - - public enum Value - { - True, - } - - public Value Known() => - _value switch - { - true => Value.True, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public bool Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AppliesToAll FromRaw(bool value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewMaximumProperties/PriceType.cs b/src/Orb/Models/NewMaximumProperties/PriceType.cs deleted file mode 100644 index 2db7c9ab..00000000 --- a/src/Orb/Models/NewMaximumProperties/PriceType.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewMaximumProperties; - -/// -/// If set, only prices of the specified type will have the adjustment applied. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType Usage = new("usage"); - - public static readonly PriceType FixedInAdvance = new("fixed_in_advance"); - - public static readonly PriceType FixedInArrears = new("fixed_in_arrears"); - - public static readonly PriceType Fixed = new("fixed"); - - public static readonly PriceType InArrears = new("in_arrears"); - - readonly string _value = value; - - public enum Value - { - Usage, - FixedInAdvance, - FixedInArrears, - Fixed, - InArrears, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - "fixed_in_advance" => Value.FixedInAdvance, - "fixed_in_arrears" => Value.FixedInArrears, - "fixed" => Value.Fixed, - "in_arrears" => Value.InArrears, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewMinimum.cs b/src/Orb/Models/NewMinimum.cs index 04d051ee..5e3fbbdb 100644 --- a/src/Orb/Models/NewMinimum.cs +++ b/src/Orb/Models/NewMinimum.cs @@ -1,30 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewMinimumProperties = Orb.Models.NewMinimumProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewMinimum : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewMinimum : JsonModel { - public required NewMinimumProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_type" + ); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// @@ -32,87 +29,53 @@ public sealed record class NewMinimum : Orb::ModelBase, Orb::IFromRaw public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } public required string MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("minimum_amount"); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } /// /// If set, the adjustment will apply to every price on the subscription. /// - public NewMinimumProperties::AppliesToAll? AppliesToAll + public ApiEnum? AppliesToAll { get { - if (!this.Properties.TryGetValue("applies_to_all", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_all" + ); } - set { this.Properties["applies_to_all"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applies_to_all", value); } } /// /// The set of item IDs to which this adjustment applies. /// - public Generic::List? AppliesToItemIDs + public IReadOnlyList? AppliesToItemIDs { get { - if (!this.Properties.TryGetValue("applies_to_item_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_item_ids"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_item_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_item_ids", value); } } /// /// The set of price IDs to which this adjustment applies. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// @@ -120,79 +83,61 @@ public required string MinimumAmount /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// A list of filters that determine which prices this adjustment will apply to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { - get - { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass>(this.RawData, "filters"); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// When false, this adjustment will be applied to a single price. Otherwise, it - /// will be applied at the invoice level, possibly to multiple prices. + /// When false, this adjustment will be applied to a single price. Otherwise, + /// it will be applied at the invoice level, possibly to multiple prices. /// public bool? IsInvoiceLevel { - get + get { return JsonModel.GetNullableStruct(this.RawData, "is_invoice_level"); } + init { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// /// If set, only prices of the specified type will have the adjustment applied. /// - public NewMinimumProperties::PriceType? PriceType + public ApiEnum? PriceType { get { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass>( + this.RawData, + "price_type" + ); } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_type", value); } } + /// public override void Validate() { this.AdjustmentType.Validate(); _ = this.ItemID; _ = this.MinimumAmount; this.AppliesToAll?.Validate(); - foreach (var item in this.AppliesToItemIDs ?? []) - { - _ = item; - } - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToItemIDs; + _ = this.AppliesToPriceIDs; _ = this.Currency; foreach (var item in this.Filters ?? []) { @@ -204,18 +149,360 @@ public override void Validate() public NewMinimum() { } + public NewMinimum(NewMinimum newMinimum) + : base(newMinimum) { } + + public NewMinimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewMinimum(Generic::Dictionary properties) + [SetsRequiredMembers] + NewMinimum(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewMinimum FromRawUnchecked( - Generic::Dictionary properties + /// + public static NewMinimum FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewMinimumFromRaw : IFromRawJson +{ + /// + public NewMinimum FromRawUnchecked(IReadOnlyDictionary rawData) => + NewMinimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewMinimumAdjustmentTypeConverter))] +public enum NewMinimumAdjustmentType +{ + Minimum, +} + +sealed class NewMinimumAdjustmentTypeConverter : JsonConverter +{ + public override NewMinimumAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "minimum" => NewMinimumAdjustmentType.Minimum, + _ => (NewMinimumAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMinimumAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMinimumAdjustmentType.Minimum => "minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, the adjustment will apply to every price on the subscription. +/// +[JsonConverter(typeof(NewMinimumAppliesToAllConverter))] +public enum NewMinimumAppliesToAll +{ + True, +} + +sealed class NewMinimumAppliesToAllConverter : JsonConverter +{ + public override NewMinimumAppliesToAll Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + true => NewMinimumAppliesToAll.True, + _ => (NewMinimumAppliesToAll)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMinimumAppliesToAll value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMinimumAppliesToAll.True => true, + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewMinimumFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public NewMinimumFilter() { } + + public NewMinimumFilter(NewMinimumFilter newMinimumFilter) + : base(newMinimumFilter) { } + + public NewMinimumFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewMinimumFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewMinimumFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewMinimumFilterFromRaw : IFromRawJson +{ + /// + public NewMinimumFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + NewMinimumFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(NewMinimumFilterFieldConverter))] +public enum NewMinimumFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class NewMinimumFilterFieldConverter : JsonConverter +{ + public override NewMinimumFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => NewMinimumFilterField.PriceID, + "item_id" => NewMinimumFilterField.ItemID, + "price_type" => NewMinimumFilterField.PriceType, + "currency" => NewMinimumFilterField.Currency, + "pricing_unit_id" => NewMinimumFilterField.PricingUnitID, + _ => (NewMinimumFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMinimumFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMinimumFilterField.PriceID => "price_id", + NewMinimumFilterField.ItemID => "item_id", + NewMinimumFilterField.PriceType => "price_type", + NewMinimumFilterField.Currency => "currency", + NewMinimumFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(NewMinimumFilterOperatorConverter))] +public enum NewMinimumFilterOperator +{ + Includes, + Excludes, +} + +sealed class NewMinimumFilterOperatorConverter : JsonConverter +{ + public override NewMinimumFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => NewMinimumFilterOperator.Includes, + "excludes" => NewMinimumFilterOperator.Excludes, + _ => (NewMinimumFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMinimumFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewMinimumFilterOperator.Includes => "includes", + NewMinimumFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, only prices of the specified type will have the adjustment applied. +/// +[JsonConverter(typeof(NewMinimumPriceTypeConverter))] +public enum NewMinimumPriceType +{ + Usage, + FixedInAdvance, + FixedInArrears, + Fixed, + InArrears, +} + +sealed class NewMinimumPriceTypeConverter : JsonConverter +{ + public override NewMinimumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => NewMinimumPriceType.Usage, + "fixed_in_advance" => NewMinimumPriceType.FixedInAdvance, + "fixed_in_arrears" => NewMinimumPriceType.FixedInArrears, + "fixed" => NewMinimumPriceType.Fixed, + "in_arrears" => NewMinimumPriceType.InArrears, + _ => (NewMinimumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewMinimumPriceType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewMinimumPriceType.Usage => "usage", + NewMinimumPriceType.FixedInAdvance => "fixed_in_advance", + NewMinimumPriceType.FixedInArrears => "fixed_in_arrears", + NewMinimumPriceType.Fixed => "fixed", + NewMinimumPriceType.InArrears => "in_arrears", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewMinimumProperties/AdjustmentType.cs b/src/Orb/Models/NewMinimumProperties/AdjustmentType.cs deleted file mode 100644 index 49d7b6f2..00000000 --- a/src/Orb/Models/NewMinimumProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType Minimum = new("minimum"); - - readonly string _value = value; - - public enum Value - { - Minimum, - } - - public Value Known() => - _value switch - { - "minimum" => Value.Minimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewMinimumProperties/AppliesToAll.cs b/src/Orb/Models/NewMinimumProperties/AppliesToAll.cs deleted file mode 100644 index 3ec34a37..00000000 --- a/src/Orb/Models/NewMinimumProperties/AppliesToAll.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewMinimumProperties; - -/// -/// If set, the adjustment will apply to every price on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AppliesToAll(bool value) : Orb::IEnum -{ - public static readonly AppliesToAll True = new(true); - - readonly bool _value = value; - - public enum Value - { - True, - } - - public Value Known() => - _value switch - { - true => Value.True, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public bool Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AppliesToAll FromRaw(bool value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewMinimumProperties/PriceType.cs b/src/Orb/Models/NewMinimumProperties/PriceType.cs deleted file mode 100644 index 15ac6dc8..00000000 --- a/src/Orb/Models/NewMinimumProperties/PriceType.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewMinimumProperties; - -/// -/// If set, only prices of the specified type will have the adjustment applied. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType Usage = new("usage"); - - public static readonly PriceType FixedInAdvance = new("fixed_in_advance"); - - public static readonly PriceType FixedInArrears = new("fixed_in_arrears"); - - public static readonly PriceType Fixed = new("fixed"); - - public static readonly PriceType InArrears = new("in_arrears"); - - readonly string _value = value; - - public enum Value - { - Usage, - FixedInAdvance, - FixedInArrears, - Fixed, - InArrears, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - "fixed_in_advance" => Value.FixedInAdvance, - "fixed_in_arrears" => Value.FixedInArrears, - "fixed" => Value.Fixed, - "in_arrears" => Value.InArrears, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPercentageDiscount.cs b/src/Orb/Models/NewPercentageDiscount.cs index 3652eb2a..39f9ba7d 100644 --- a/src/Orb/Models/NewPercentageDiscount.cs +++ b/src/Orb/Models/NewPercentageDiscount.cs @@ -1,106 +1,72 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPercentageDiscountProperties = Orb.Models.NewPercentageDiscountProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPercentageDiscount - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewPercentageDiscount : JsonModel { - public required NewPercentageDiscountProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_type" + ); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } public required double PercentageDiscount { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } } /// /// If set, the adjustment will apply to every price on the subscription. /// - public NewPercentageDiscountProperties::AppliesToAll? AppliesToAll + public ApiEnum? AppliesToAll { get { - if (!this.Properties.TryGetValue("applies_to_all", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_all" ); } - set { this.Properties["applies_to_all"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applies_to_all", value); } } /// /// The set of item IDs to which this adjustment applies. /// - public Generic::List? AppliesToItemIDs + public IReadOnlyList? AppliesToItemIDs { get { - if (!this.Properties.TryGetValue("applies_to_item_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_item_ids"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_item_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_item_ids", value); } } /// /// The set of price IDs to which this adjustment applies. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// @@ -108,80 +74,66 @@ public required double PercentageDiscount /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// A list of filters that determine which prices this adjustment will apply to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// When false, this adjustment will be applied to a single price. Otherwise, it - /// will be applied at the invoice level, possibly to multiple prices. + /// When false, this adjustment will be applied to a single price. Otherwise, + /// it will be applied at the invoice level, possibly to multiple prices. /// public bool? IsInvoiceLevel { - get + get { return JsonModel.GetNullableStruct(this.RawData, "is_invoice_level"); } + init { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// /// If set, only prices of the specified type will have the adjustment applied. /// - public NewPercentageDiscountProperties::PriceType? PriceType + public ApiEnum? PriceType { get { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "price_type" ); } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_type", value); } } + /// public override void Validate() { this.AdjustmentType.Validate(); _ = this.PercentageDiscount; this.AppliesToAll?.Validate(); - foreach (var item in this.AppliesToItemIDs ?? []) - { - _ = item; - } - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToItemIDs; + _ = this.AppliesToPriceIDs; _ = this.Currency; foreach (var item in this.Filters ?? []) { @@ -193,18 +145,370 @@ public override void Validate() public NewPercentageDiscount() { } + public NewPercentageDiscount(NewPercentageDiscount newPercentageDiscount) + : base(newPercentageDiscount) { } + + public NewPercentageDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPercentageDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPercentageDiscount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPercentageDiscount FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPercentageDiscountFromRaw : IFromRawJson +{ + /// + public NewPercentageDiscount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPercentageDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewPercentageDiscountAdjustmentTypeConverter))] +public enum NewPercentageDiscountAdjustmentType +{ + PercentageDiscount, +} + +sealed class NewPercentageDiscountAdjustmentTypeConverter + : JsonConverter +{ + public override NewPercentageDiscountAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage_discount" => NewPercentageDiscountAdjustmentType.PercentageDiscount, + _ => (NewPercentageDiscountAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPercentageDiscountAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPercentageDiscountAdjustmentType.PercentageDiscount => "percentage_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, the adjustment will apply to every price on the subscription. +/// +[JsonConverter(typeof(NewPercentageDiscountAppliesToAllConverter))] +public enum NewPercentageDiscountAppliesToAll +{ + True, +} + +sealed class NewPercentageDiscountAppliesToAllConverter + : JsonConverter +{ + public override NewPercentageDiscountAppliesToAll Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + true => NewPercentageDiscountAppliesToAll.True, + _ => (NewPercentageDiscountAppliesToAll)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPercentageDiscountAppliesToAll value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPercentageDiscountAppliesToAll.True => true, + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPercentageDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public NewPercentageDiscountFilter() { } + + public NewPercentageDiscountFilter(NewPercentageDiscountFilter newPercentageDiscountFilter) + : base(newPercentageDiscountFilter) { } + + public NewPercentageDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPercentageDiscountFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPercentageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPercentageDiscountFilterFromRaw : IFromRawJson +{ + /// + public NewPercentageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPercentageDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(NewPercentageDiscountFilterFieldConverter))] +public enum NewPercentageDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class NewPercentageDiscountFilterFieldConverter + : JsonConverter +{ + public override NewPercentageDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => NewPercentageDiscountFilterField.PriceID, + "item_id" => NewPercentageDiscountFilterField.ItemID, + "price_type" => NewPercentageDiscountFilterField.PriceType, + "currency" => NewPercentageDiscountFilterField.Currency, + "pricing_unit_id" => NewPercentageDiscountFilterField.PricingUnitID, + _ => (NewPercentageDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPercentageDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPercentageDiscountFilterField.PriceID => "price_id", + NewPercentageDiscountFilterField.ItemID => "item_id", + NewPercentageDiscountFilterField.PriceType => "price_type", + NewPercentageDiscountFilterField.Currency => "currency", + NewPercentageDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(NewPercentageDiscountFilterOperatorConverter))] +public enum NewPercentageDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class NewPercentageDiscountFilterOperatorConverter + : JsonConverter +{ + public override NewPercentageDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => NewPercentageDiscountFilterOperator.Includes, + "excludes" => NewPercentageDiscountFilterOperator.Excludes, + _ => (NewPercentageDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPercentageDiscountFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPercentageDiscountFilterOperator.Includes => "includes", + NewPercentageDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, only prices of the specified type will have the adjustment applied. +/// +[JsonConverter(typeof(NewPercentageDiscountPriceTypeConverter))] +public enum NewPercentageDiscountPriceType +{ + Usage, + FixedInAdvance, + FixedInArrears, + Fixed, + InArrears, +} + +sealed class NewPercentageDiscountPriceTypeConverter : JsonConverter +{ + public override NewPercentageDiscountPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => NewPercentageDiscountPriceType.Usage, + "fixed_in_advance" => NewPercentageDiscountPriceType.FixedInAdvance, + "fixed_in_arrears" => NewPercentageDiscountPriceType.FixedInArrears, + "fixed" => NewPercentageDiscountPriceType.Fixed, + "in_arrears" => NewPercentageDiscountPriceType.InArrears, + _ => (NewPercentageDiscountPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPercentageDiscountPriceType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewPercentageDiscountPriceType.Usage => "usage", + NewPercentageDiscountPriceType.FixedInAdvance => "fixed_in_advance", + NewPercentageDiscountPriceType.FixedInArrears => "fixed_in_arrears", + NewPercentageDiscountPriceType.Fixed => "fixed", + NewPercentageDiscountPriceType.InArrears => "in_arrears", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewPercentageDiscountProperties/AdjustmentType.cs b/src/Orb/Models/NewPercentageDiscountProperties/AdjustmentType.cs deleted file mode 100644 index 440c0e12..00000000 --- a/src/Orb/Models/NewPercentageDiscountProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPercentageDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType PercentageDiscount = new("percentage_discount"); - - readonly string _value = value; - - public enum Value - { - PercentageDiscount, - } - - public Value Known() => - _value switch - { - "percentage_discount" => Value.PercentageDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPercentageDiscountProperties/AppliesToAll.cs b/src/Orb/Models/NewPercentageDiscountProperties/AppliesToAll.cs deleted file mode 100644 index 47f42673..00000000 --- a/src/Orb/Models/NewPercentageDiscountProperties/AppliesToAll.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPercentageDiscountProperties; - -/// -/// If set, the adjustment will apply to every price on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AppliesToAll(bool value) : Orb::IEnum -{ - public static readonly AppliesToAll True = new(true); - - readonly bool _value = value; - - public enum Value - { - True, - } - - public Value Known() => - _value switch - { - true => Value.True, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public bool Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AppliesToAll FromRaw(bool value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPercentageDiscountProperties/PriceType.cs b/src/Orb/Models/NewPercentageDiscountProperties/PriceType.cs deleted file mode 100644 index 7ca0643b..00000000 --- a/src/Orb/Models/NewPercentageDiscountProperties/PriceType.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPercentageDiscountProperties; - -/// -/// If set, only prices of the specified type will have the adjustment applied. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType Usage = new("usage"); - - public static readonly PriceType FixedInAdvance = new("fixed_in_advance"); - - public static readonly PriceType FixedInArrears = new("fixed_in_arrears"); - - public static readonly PriceType Fixed = new("fixed"); - - public static readonly PriceType InArrears = new("in_arrears"); - - readonly string _value = value; - - public enum Value - { - Usage, - FixedInAdvance, - FixedInArrears, - Fixed, - InArrears, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - "fixed_in_advance" => Value.FixedInAdvance, - "fixed_in_arrears" => Value.FixedInArrears, - "fixed" => Value.Fixed, - "in_arrears" => Value.InArrears, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBPSPrice.cs b/src/Orb/Models/NewPlanBPSPrice.cs deleted file mode 100644 index b6c83e65..00000000 --- a/src/Orb/Models/NewPlanBPSPrice.cs +++ /dev/null @@ -1,403 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanBPSPriceProperties = Orb.Models.NewPlanBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanBPSPrice : Orb::ModelBase, Orb::IFromRaw -{ - public required BPSConfig BPSConfig - { - get - { - if (!this.Properties.TryGetValue("bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bps_config"); - } - set { this.Properties["bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The cadence to bill for this price on. - /// - public required NewPlanBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewPlanBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewPlanBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewPlanBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewPlanBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewPlanBPSPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanBPSPriceProperties/Cadence.cs deleted file mode 100644 index a9ebcf15..00000000 --- a/src/Orb/Models/NewPlanBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index c1fcdde2..00000000 --- a/src/Orb/Models/NewPlanBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 50b72d11..00000000 --- a/src/Orb/Models/NewPlanBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanBPSPriceProperties = Orb.Models.NewPlanBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanBPSPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanBPSPriceProperties/ModelType.cs deleted file mode 100644 index a84f7656..00000000 --- a/src/Orb/Models/NewPlanBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BPS = new("bps"); - - readonly string _value = value; - - public enum Value - { - BPS, - } - - public Value Known() => - _value switch - { - "bps" => Value.BPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBulkBPSPrice.cs b/src/Orb/Models/NewPlanBulkBPSPrice.cs deleted file mode 100644 index a428001d..00000000 --- a/src/Orb/Models/NewPlanBulkBPSPrice.cs +++ /dev/null @@ -1,404 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanBulkBPSPriceProperties = Orb.Models.NewPlanBulkBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanBulkBPSPrice : Orb::ModelBase, Orb::IFromRaw -{ - public required BulkBPSConfig BulkBPSConfig - { - get - { - if (!this.Properties.TryGetValue("bulk_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_bps_config"); - } - set { this.Properties["bulk_bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The cadence to bill for this price on. - /// - public required NewPlanBulkBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewPlanBulkBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewPlanBulkBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BulkBPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewPlanBulkBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanBulkBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewPlanBulkBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewPlanBulkBPSPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanBulkBPSPriceProperties/Cadence.cs deleted file mode 100644 index 67b75234..00000000 --- a/src/Orb/Models/NewPlanBulkBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBulkBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBulkBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanBulkBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index f1215e94..00000000 --- a/src/Orb/Models/NewPlanBulkBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanBulkBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBulkBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 589c0cfa..00000000 --- a/src/Orb/Models/NewPlanBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanBulkBPSPriceProperties = Orb.Models.NewPlanBulkBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBulkBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanBulkBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanBulkBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanBulkBPSPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanBulkBPSPriceProperties/ModelType.cs deleted file mode 100644 index f52acc5c..00000000 --- a/src/Orb/Models/NewPlanBulkBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBulkBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkBPS = new("bulk_bps"); - - readonly string _value = value; - - public enum Value - { - BulkBPS, - } - - public Value Known() => - _value switch - { - "bulk_bps" => Value.BulkBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBulkPrice.cs b/src/Orb/Models/NewPlanBulkPrice.cs index eb59b823..82663ee1 100644 --- a/src/Orb/Models/NewPlanBulkPrice.cs +++ b/src/Orb/Models/NewPlanBulkPrice.cs @@ -1,49 +1,39 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanBulkPriceProperties = Orb.Models.NewPlanBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanBulkPrice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewPlanBulkPrice : JsonModel { + /// + /// Configuration for bulk pricing + /// public required BulkConfig BulkConfig { - get - { - if (!this.Properties.TryGetValue("bulk_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_config"); - } - set { this.Properties["bulk_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "bulk_config"); } + init { JsonModel.Set(this._rawData, "bulk_config", value); } } /// /// The cadence to bill for this price on. /// - public required NewPlanBulkPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -51,34 +41,23 @@ public required BulkConfig BulkConfig /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanBulkPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -86,15 +65,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -102,60 +74,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -163,57 +109,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanBulkPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanBulkPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -223,21 +145,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -245,17 +158,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -263,19 +167,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -283,19 +176,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -306,21 +188,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -328,16 +201,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -346,16 +219,11 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.BulkConfig.Validate(); @@ -374,30 +242,419 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanBulkPrice() { } + public NewPlanBulkPrice(NewPlanBulkPrice newPlanBulkPrice) + : base(newPlanBulkPrice) { } + + public NewPlanBulkPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanBulkPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanBulkPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanBulkPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanBulkPriceFromRaw : IFromRawJson +{ + /// + public NewPlanBulkPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + NewPlanBulkPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanBulkPriceCadenceConverter))] +public enum NewPlanBulkPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanBulkPriceCadenceConverter : JsonConverter +{ + public override NewPlanBulkPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanBulkPriceCadence.Annual, + "semi_annual" => NewPlanBulkPriceCadence.SemiAnnual, + "monthly" => NewPlanBulkPriceCadence.Monthly, + "quarterly" => NewPlanBulkPriceCadence.Quarterly, + "one_time" => NewPlanBulkPriceCadence.OneTime, + "custom" => NewPlanBulkPriceCadence.Custom, + _ => (NewPlanBulkPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanBulkPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanBulkPriceCadence.Annual => "annual", + NewPlanBulkPriceCadence.SemiAnnual => "semi_annual", + NewPlanBulkPriceCadence.Monthly => "monthly", + NewPlanBulkPriceCadence.Quarterly => "quarterly", + NewPlanBulkPriceCadence.OneTime => "one_time", + NewPlanBulkPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanBulkPriceModelTypeConverter))] +public enum NewPlanBulkPriceModelType +{ + Bulk, +} + +sealed class NewPlanBulkPriceModelTypeConverter : JsonConverter +{ + public override NewPlanBulkPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "bulk" => NewPlanBulkPriceModelType.Bulk, + _ => (NewPlanBulkPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanBulkPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanBulkPriceModelType.Bulk => "bulk", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanBulkPriceConversionRateConfigConverter))] +public record class NewPlanBulkPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanBulkPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanBulkPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanBulkPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanBulkPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanBulkPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanBulkPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanBulkPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanBulkPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanBulkPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanBulkPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanBulkPriceProperties/Cadence.cs deleted file mode 100644 index a7837baa..00000000 --- a/src/Orb/Models/NewPlanBulkPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBulkPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBulkPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanBulkPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 4c8893da..00000000 --- a/src/Orb/Models/NewPlanBulkPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanBulkPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBulkPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanBulkPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanBulkPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8453a2af..00000000 --- a/src/Orb/Models/NewPlanBulkPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanBulkPriceProperties = Orb.Models.NewPlanBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBulkPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanBulkPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanBulkPriceProperties/ModelType.cs deleted file mode 100644 index 386dacdc..00000000 --- a/src/Orb/Models/NewPlanBulkPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBulkPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Bulk = new("bulk"); - - readonly string _value = value; - - public enum Value - { - Bulk, - } - - public Value Known() => - _value switch - { - "bulk" => Value.Bulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBulkWithProrationPrice.cs b/src/Orb/Models/NewPlanBulkWithProrationPrice.cs index c1df4585..20ff8310 100644 --- a/src/Orb/Models/NewPlanBulkWithProrationPrice.cs +++ b/src/Orb/Models/NewPlanBulkWithProrationPrice.cs @@ -1,63 +1,47 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanBulkWithProrationPriceProperties = Orb.Models.NewPlanBulkWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanBulkWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanBulkWithProrationPrice : JsonModel { - public required Generic::Dictionary BulkWithProrationConfig + /// + /// Configuration for bulk_with_proration pricing + /// + public required NewPlanBulkWithProrationPriceBulkWithProrationConfig BulkWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "bulk_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "bulk_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("bulk_with_proration_config"); - } - set - { - this.Properties["bulk_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_proration_config" ); } + init { JsonModel.Set(this._rawData, "bulk_with_proration_config", value); } } /// /// The cadence to bill for this price on. /// - public required NewPlanBulkWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -65,35 +49,22 @@ public sealed record class NewPlanBulkWithProrationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanBulkWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -101,15 +72,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -117,60 +81,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -178,57 +116,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanBulkWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanBulkWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -238,21 +152,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +165,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +174,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +183,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +195,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +208,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,22 +226,14 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { - foreach (var item in this.BulkWithProrationConfig.Values) - { - _ = item; - } + this.BulkWithProrationConfig.Validate(); this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); @@ -392,30 +249,594 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanBulkWithProrationPrice() { } + public NewPlanBulkWithProrationPrice( + NewPlanBulkWithProrationPrice newPlanBulkWithProrationPrice + ) + : base(newPlanBulkWithProrationPrice) { } + + public NewPlanBulkWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanBulkWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanBulkWithProrationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanBulkWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanBulkWithProrationPriceFromRaw : IFromRawJson +{ + /// + public NewPlanBulkWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanBulkWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanBulkWithProrationPriceBulkWithProrationConfig, + NewPlanBulkWithProrationPriceBulkWithProrationConfigFromRaw + >) +)] +public sealed record class NewPlanBulkWithProrationPriceBulkWithProrationConfig : JsonModel +{ + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public NewPlanBulkWithProrationPriceBulkWithProrationConfig() { } + + public NewPlanBulkWithProrationPriceBulkWithProrationConfig( + NewPlanBulkWithProrationPriceBulkWithProrationConfig newPlanBulkWithProrationPriceBulkWithProrationConfig + ) + : base(newPlanBulkWithProrationPriceBulkWithProrationConfig) { } + + public NewPlanBulkWithProrationPriceBulkWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanBulkWithProrationPriceBulkWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanBulkWithProrationPriceBulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewPlanBulkWithProrationPriceBulkWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class NewPlanBulkWithProrationPriceBulkWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanBulkWithProrationPriceBulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanBulkWithProrationPriceBulkWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier with proration +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanBulkWithProrationPriceBulkWithProrationConfigTier, + NewPlanBulkWithProrationPriceBulkWithProrationConfigTierFromRaw + >) +)] +public sealed record class NewPlanBulkWithProrationPriceBulkWithProrationConfigTier : JsonModel +{ + /// + /// Cost per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public NewPlanBulkWithProrationPriceBulkWithProrationConfigTier() { } + + public NewPlanBulkWithProrationPriceBulkWithProrationConfigTier( + NewPlanBulkWithProrationPriceBulkWithProrationConfigTier newPlanBulkWithProrationPriceBulkWithProrationConfigTier + ) + : base(newPlanBulkWithProrationPriceBulkWithProrationConfigTier) { } + + public NewPlanBulkWithProrationPriceBulkWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanBulkWithProrationPriceBulkWithProrationConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanBulkWithProrationPriceBulkWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewPlanBulkWithProrationPriceBulkWithProrationConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class NewPlanBulkWithProrationPriceBulkWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanBulkWithProrationPriceBulkWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanBulkWithProrationPriceBulkWithProrationConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanBulkWithProrationPriceCadenceConverter))] +public enum NewPlanBulkWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanBulkWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewPlanBulkWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanBulkWithProrationPriceCadence.Annual, + "semi_annual" => NewPlanBulkWithProrationPriceCadence.SemiAnnual, + "monthly" => NewPlanBulkWithProrationPriceCadence.Monthly, + "quarterly" => NewPlanBulkWithProrationPriceCadence.Quarterly, + "one_time" => NewPlanBulkWithProrationPriceCadence.OneTime, + "custom" => NewPlanBulkWithProrationPriceCadence.Custom, + _ => (NewPlanBulkWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanBulkWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanBulkWithProrationPriceCadence.Annual => "annual", + NewPlanBulkWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewPlanBulkWithProrationPriceCadence.Monthly => "monthly", + NewPlanBulkWithProrationPriceCadence.Quarterly => "quarterly", + NewPlanBulkWithProrationPriceCadence.OneTime => "one_time", + NewPlanBulkWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanBulkWithProrationPriceModelTypeConverter))] +public enum NewPlanBulkWithProrationPriceModelType +{ + BulkWithProration, +} + +sealed class NewPlanBulkWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanBulkWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "bulk_with_proration" => NewPlanBulkWithProrationPriceModelType.BulkWithProration, + _ => (NewPlanBulkWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanBulkWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanBulkWithProrationPriceModelType.BulkWithProration => "bulk_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanBulkWithProrationPriceConversionRateConfigConverter))] +public record class NewPlanBulkWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanBulkWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanBulkWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanBulkWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanBulkWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanBulkWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanBulkWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanBulkWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanBulkWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanBulkWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanBulkWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanBulkWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanBulkWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanBulkWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index e45107eb..00000000 --- a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBulkWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 55eedc4c..00000000 --- a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanBulkWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBulkWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 16623954..00000000 --- a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanBulkWithProrationPriceProperties = Orb.Models.NewPlanBulkWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanBulkWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanBulkWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanBulkWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index c92b7385..00000000 --- a/src/Orb/Models/NewPlanBulkWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanBulkWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkWithProration = new("bulk_with_proration"); - - readonly string _value = value; - - public enum Value - { - BulkWithProration, - } - - public Value Known() => - _value switch - { - "bulk_with_proration" => Value.BulkWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanCumulativeGroupedBulkPrice.cs b/src/Orb/Models/NewPlanCumulativeGroupedBulkPrice.cs index a0f68cba..78097f27 100644 --- a/src/Orb/Models/NewPlanCumulativeGroupedBulkPrice.cs +++ b/src/Orb/Models/NewPlanCumulativeGroupedBulkPrice.cs @@ -1,62 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanCumulativeGroupedBulkPriceProperties = Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanCumulativeGroupedBulkPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanCumulativeGroupedBulkPrice, + NewPlanCumulativeGroupedBulkPriceFromRaw + >) +)] +public sealed record class NewPlanCumulativeGroupedBulkPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanCumulativeGroupedBulkPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary CumulativeGroupedBulkConfig + /// + /// Configuration for cumulative_grouped_bulk pricing + /// + public required NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig CumulativeGroupedBulkConfig { get { - if ( - !this.Properties.TryGetValue( - "cumulative_grouped_bulk_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "cumulative_grouped_bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("cumulative_grouped_bulk_config"); - } - set - { - this.Properties["cumulative_grouped_bulk_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_bulk_config" + ); } + init { JsonModel.Set(this._rawData, "cumulative_grouped_bulk_config", value); } } /// @@ -64,35 +51,22 @@ public sealed record class NewPlanCumulativeGroupedBulkPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanCumulativeGroupedBulkPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -100,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanCumulativeGroupedBulkPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanCumulativeGroupedBulkPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,23 +228,15 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.CumulativeGroupedBulkConfig.Values) - { - _ = item; - } + this.CumulativeGroupedBulkConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -391,30 +251,604 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanCumulativeGroupedBulkPrice() { } + public NewPlanCumulativeGroupedBulkPrice( + NewPlanCumulativeGroupedBulkPrice newPlanCumulativeGroupedBulkPrice + ) + : base(newPlanCumulativeGroupedBulkPrice) { } + + public NewPlanCumulativeGroupedBulkPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanCumulativeGroupedBulkPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanCumulativeGroupedBulkPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanCumulativeGroupedBulkPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanCumulativeGroupedBulkPriceFromRaw : IFromRawJson +{ + /// + public NewPlanCumulativeGroupedBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanCumulativeGroupedBulkPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanCumulativeGroupedBulkPriceCadenceConverter))] +public enum NewPlanCumulativeGroupedBulkPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanCumulativeGroupedBulkPriceCadenceConverter + : JsonConverter +{ + public override NewPlanCumulativeGroupedBulkPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanCumulativeGroupedBulkPriceCadence.Annual, + "semi_annual" => NewPlanCumulativeGroupedBulkPriceCadence.SemiAnnual, + "monthly" => NewPlanCumulativeGroupedBulkPriceCadence.Monthly, + "quarterly" => NewPlanCumulativeGroupedBulkPriceCadence.Quarterly, + "one_time" => NewPlanCumulativeGroupedBulkPriceCadence.OneTime, + "custom" => NewPlanCumulativeGroupedBulkPriceCadence.Custom, + _ => (NewPlanCumulativeGroupedBulkPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanCumulativeGroupedBulkPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanCumulativeGroupedBulkPriceCadence.Annual => "annual", + NewPlanCumulativeGroupedBulkPriceCadence.SemiAnnual => "semi_annual", + NewPlanCumulativeGroupedBulkPriceCadence.Monthly => "monthly", + NewPlanCumulativeGroupedBulkPriceCadence.Quarterly => "quarterly", + NewPlanCumulativeGroupedBulkPriceCadence.OneTime => "one_time", + NewPlanCumulativeGroupedBulkPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_bulk pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig, + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigFromRaw + >) +)] +public sealed record class NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig : JsonModel +{ + /// + /// Each tier lower bound must have the same group of values. + /// + public required IReadOnlyList DimensionValues + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "dimension_values"); + } + init { JsonModel.Set(this._rawData, "dimension_values", value); } + } + + /// + /// Grouping key name + /// + public required string Group + { + get { return JsonModel.GetNotNullClass(this.RawData, "group"); } + init { JsonModel.Set(this._rawData, "group", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.DimensionValues) + { + item.Validate(); + } + _ = this.Group; + } + + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig() { } + + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig( + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig newPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig + ) + : base(newPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig) { } + + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a dimension value entry +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue, + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValueFromRaw + >) +)] +public sealed record class NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue + : JsonModel +{ + /// + /// Grouping key value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Unit amount for this combination + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue() { } + + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue( + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue newPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue + ) + : base(newPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue) { } + + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValueFromRaw + : IFromRawJson +{ + /// + public NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanCumulativeGroupedBulkPriceCumulativeGroupedBulkConfigDimensionValue.FromRawUnchecked( + rawData + ); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanCumulativeGroupedBulkPriceModelTypeConverter))] +public enum NewPlanCumulativeGroupedBulkPriceModelType +{ + CumulativeGroupedBulk, +} + +sealed class NewPlanCumulativeGroupedBulkPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanCumulativeGroupedBulkPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "cumulative_grouped_bulk" => + NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + _ => (NewPlanCumulativeGroupedBulkPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanCumulativeGroupedBulkPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk => + "cumulative_grouped_bulk", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanCumulativeGroupedBulkPriceConversionRateConfigConverter))] +public record class NewPlanCumulativeGroupedBulkPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanCumulativeGroupedBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanCumulativeGroupedBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanCumulativeGroupedBulkPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanCumulativeGroupedBulkPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanCumulativeGroupedBulkPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanCumulativeGroupedBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanCumulativeGroupedBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanCumulativeGroupedBulkPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanCumulativeGroupedBulkPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanCumulativeGroupedBulkPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanCumulativeGroupedBulkPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanCumulativeGroupedBulkPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanCumulativeGroupedBulkPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/Cadence.cs deleted file mode 100644 index dc5fb5a7..00000000 --- a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 576958ee..00000000 --- a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 838a16c6..00000000 --- a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanCumulativeGroupedBulkPriceProperties = Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanCumulativeGroupedBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanCumulativeGroupedBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ModelType.cs deleted file mode 100644 index 23551e1d..00000000 --- a/src/Orb/Models/NewPlanCumulativeGroupedBulkPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanCumulativeGroupedBulkPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType CumulativeGroupedBulk = new("cumulative_grouped_bulk"); - - readonly string _value = value; - - public enum Value - { - CumulativeGroupedBulk, - } - - public Value Known() => - _value switch - { - "cumulative_grouped_bulk" => Value.CumulativeGroupedBulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedAllocationPrice.cs b/src/Orb/Models/NewPlanGroupedAllocationPrice.cs index b573a499..9af05e89 100644 --- a/src/Orb/Models/NewPlanGroupedAllocationPrice.cs +++ b/src/Orb/Models/NewPlanGroupedAllocationPrice.cs @@ -1,63 +1,47 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanGroupedAllocationPriceProperties = Orb.Models.NewPlanGroupedAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanGroupedAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanGroupedAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanGroupedAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedAllocationConfig + /// + /// Configuration for grouped_allocation pricing + /// + public required NewPlanGroupedAllocationPriceGroupedAllocationConfig GroupedAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_allocation_config"); - } - set - { - this.Properties["grouped_allocation_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_allocation_config" ); } + init { JsonModel.Set(this._rawData, "grouped_allocation_config", value); } } /// @@ -65,35 +49,22 @@ public sealed record class NewPlanGroupedAllocationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanGroupedAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -101,15 +72,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -117,60 +81,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -178,57 +116,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanGroupedAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanGroupedAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -238,21 +152,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +165,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +174,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +183,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +195,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +208,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,23 +226,15 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedAllocationConfig.Values) - { - _ = item; - } + this.GroupedAllocationConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -392,30 +249,512 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanGroupedAllocationPrice() { } + public NewPlanGroupedAllocationPrice( + NewPlanGroupedAllocationPrice newPlanGroupedAllocationPrice + ) + : base(newPlanGroupedAllocationPrice) { } + + public NewPlanGroupedAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanGroupedAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanGroupedAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanGroupedAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedAllocationPriceFromRaw : IFromRawJson +{ + /// + public NewPlanGroupedAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanGroupedAllocationPriceCadenceConverter))] +public enum NewPlanGroupedAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanGroupedAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewPlanGroupedAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanGroupedAllocationPriceCadence.Annual, + "semi_annual" => NewPlanGroupedAllocationPriceCadence.SemiAnnual, + "monthly" => NewPlanGroupedAllocationPriceCadence.Monthly, + "quarterly" => NewPlanGroupedAllocationPriceCadence.Quarterly, + "one_time" => NewPlanGroupedAllocationPriceCadence.OneTime, + "custom" => NewPlanGroupedAllocationPriceCadence.Custom, + _ => (NewPlanGroupedAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedAllocationPriceCadence.Annual => "annual", + NewPlanGroupedAllocationPriceCadence.SemiAnnual => "semi_annual", + NewPlanGroupedAllocationPriceCadence.Monthly => "monthly", + NewPlanGroupedAllocationPriceCadence.Quarterly => "quarterly", + NewPlanGroupedAllocationPriceCadence.OneTime => "one_time", + NewPlanGroupedAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedAllocationPriceGroupedAllocationConfig, + NewPlanGroupedAllocationPriceGroupedAllocationConfigFromRaw + >) +)] +public sealed record class NewPlanGroupedAllocationPriceGroupedAllocationConfig : JsonModel +{ + /// + /// Usage allocation per group + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// How to determine the groups that should each be allocated some quantity + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Unit rate for post-allocation + /// + public required string OverageUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "overage_unit_rate"); } + init { JsonModel.Set(this._rawData, "overage_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.GroupingKey; + _ = this.OverageUnitRate; + } + + public NewPlanGroupedAllocationPriceGroupedAllocationConfig() { } + + public NewPlanGroupedAllocationPriceGroupedAllocationConfig( + NewPlanGroupedAllocationPriceGroupedAllocationConfig newPlanGroupedAllocationPriceGroupedAllocationConfig + ) + : base(newPlanGroupedAllocationPriceGroupedAllocationConfig) { } + + public NewPlanGroupedAllocationPriceGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedAllocationPriceGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedAllocationPriceGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedAllocationPriceGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedAllocationPriceGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedAllocationPriceGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanGroupedAllocationPriceModelTypeConverter))] +public enum NewPlanGroupedAllocationPriceModelType +{ + GroupedAllocation, +} + +sealed class NewPlanGroupedAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanGroupedAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_allocation" => NewPlanGroupedAllocationPriceModelType.GroupedAllocation, + _ => (NewPlanGroupedAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedAllocationPriceModelType.GroupedAllocation => "grouped_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanGroupedAllocationPriceConversionRateConfigConverter))] +public record class NewPlanGroupedAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanGroupedAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanGroupedAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanGroupedAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanGroupedAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanGroupedAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanGroupedAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanGroupedAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 598a066d..00000000 --- a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index b01958e8..00000000 --- a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanGroupedAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index b1050831..00000000 --- a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanGroupedAllocationPriceProperties = Orb.Models.NewPlanGroupedAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanGroupedAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanGroupedAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 526cb15f..00000000 --- a/src/Orb/Models/NewPlanGroupedAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedAllocation = new("grouped_allocation"); - - readonly string _value = value; - - public enum Value - { - GroupedAllocation, - } - - public Value Known() => - _value switch - { - "grouped_allocation" => Value.GroupedAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPackagePrice.cs b/src/Orb/Models/NewPlanGroupedTieredPackagePrice.cs index 71d3aaf4..1330148c 100644 --- a/src/Orb/Models/NewPlanGroupedTieredPackagePrice.cs +++ b/src/Orb/Models/NewPlanGroupedTieredPackagePrice.cs @@ -1,62 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanGroupedTieredPackagePriceProperties = Orb.Models.NewPlanGroupedTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanGroupedTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedTieredPackagePrice, + NewPlanGroupedTieredPackagePriceFromRaw + >) +)] +public sealed record class NewPlanGroupedTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanGroupedTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedTieredPackageConfig + /// + /// Configuration for grouped_tiered_package pricing + /// + public required NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig GroupedTieredPackageConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_package_config"); - } - set - { - this.Properties["grouped_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_package_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_tiered_package_config", value); } } /// @@ -64,35 +51,22 @@ public sealed record class NewPlanGroupedTieredPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanGroupedTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -100,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanGroupedTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanGroupedTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,23 +228,15 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedTieredPackageConfig.Values) - { - _ = item; - } + this.GroupedTieredPackageConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -391,30 +251,602 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanGroupedTieredPackagePrice() { } + public NewPlanGroupedTieredPackagePrice( + NewPlanGroupedTieredPackagePrice newPlanGroupedTieredPackagePrice + ) + : base(newPlanGroupedTieredPackagePrice) { } + + public NewPlanGroupedTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanGroupedTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanGroupedTieredPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanGroupedTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedTieredPackagePriceFromRaw : IFromRawJson +{ + /// + public NewPlanGroupedTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanGroupedTieredPackagePriceCadenceConverter))] +public enum NewPlanGroupedTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanGroupedTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewPlanGroupedTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanGroupedTieredPackagePriceCadence.Annual, + "semi_annual" => NewPlanGroupedTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewPlanGroupedTieredPackagePriceCadence.Monthly, + "quarterly" => NewPlanGroupedTieredPackagePriceCadence.Quarterly, + "one_time" => NewPlanGroupedTieredPackagePriceCadence.OneTime, + "custom" => NewPlanGroupedTieredPackagePriceCadence.Custom, + _ => (NewPlanGroupedTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedTieredPackagePriceCadence.Annual => "annual", + NewPlanGroupedTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewPlanGroupedTieredPackagePriceCadence.Monthly => "monthly", + NewPlanGroupedTieredPackagePriceCadence.Quarterly => "quarterly", + NewPlanGroupedTieredPackagePriceCadence.OneTime => "one_time", + NewPlanGroupedTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig, + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigFromRaw + >) +)] +public sealed record class NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig() { } + + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig( + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig newPlanGroupedTieredPackagePriceGroupedTieredPackageConfig + ) + : base(newPlanGroupedTieredPackagePriceGroupedTieredPackageConfig) { } + + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier, + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTierFromRaw + >) +)] +public sealed record class NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier + : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier() { } + + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier( + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier newPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier + ) + : base(newPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier) { } + + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedTieredPackagePriceGroupedTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanGroupedTieredPackagePriceModelTypeConverter))] +public enum NewPlanGroupedTieredPackagePriceModelType +{ + GroupedTieredPackage, +} + +sealed class NewPlanGroupedTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewPlanGroupedTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_tiered_package" => + NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage, + _ => (NewPlanGroupedTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedTieredPackagePriceModelType.GroupedTieredPackage => + "grouped_tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanGroupedTieredPackagePriceConversionRateConfigConverter))] +public record class NewPlanGroupedTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanGroupedTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanGroupedTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanGroupedTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanGroupedTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanGroupedTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanGroupedTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanGroupedTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index b978517d..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index e5779638..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanGroupedTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index bb29c208..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanGroupedTieredPackagePriceProperties = Orb.Models.NewPlanGroupedTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanGroupedTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanGroupedTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index 2b743203..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTieredPackage = new("grouped_tiered_package"); - - readonly string _value = value; - - public enum Value - { - GroupedTieredPackage, - } - - public Value Known() => - _value switch - { - "grouped_tiered_package" => Value.GroupedTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPrice.cs b/src/Orb/Models/NewPlanGroupedTieredPrice.cs index 4e8f4f50..d9918436 100644 --- a/src/Orb/Models/NewPlanGroupedTieredPrice.cs +++ b/src/Orb/Models/NewPlanGroupedTieredPrice.cs @@ -1,60 +1,47 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanGroupedTieredPriceProperties = Orb.Models.NewPlanGroupedTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanGroupedTieredPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanGroupedTieredPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanGroupedTieredPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedTieredConfig + /// + /// Configuration for grouped_tiered pricing + /// + public required NewPlanGroupedTieredPriceGroupedTieredConfig GroupedTieredConfig { get { - if ( - !this.Properties.TryGetValue("grouped_tiered_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_config"); - } - set - { - this.Properties["grouped_tiered_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_config" ); } + init { JsonModel.Set(this._rawData, "grouped_tiered_config", value); } } /// @@ -62,35 +49,23 @@ public sealed record class NewPlanGroupedTieredPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanGroupedTieredPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -98,15 +73,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -114,60 +82,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -175,57 +117,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanGroupedTieredPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanGroupedTieredPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -235,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -257,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -275,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -295,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -318,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -340,16 +209,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -358,23 +227,15 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedTieredConfig.Values) - { - _ = item; - } + this.GroupedTieredConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -389,30 +250,582 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanGroupedTieredPrice() { } + public NewPlanGroupedTieredPrice(NewPlanGroupedTieredPrice newPlanGroupedTieredPrice) + : base(newPlanGroupedTieredPrice) { } + + public NewPlanGroupedTieredPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanGroupedTieredPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanGroupedTieredPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanGroupedTieredPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedTieredPriceFromRaw : IFromRawJson +{ + /// + public NewPlanGroupedTieredPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedTieredPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanGroupedTieredPriceCadenceConverter))] +public enum NewPlanGroupedTieredPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanGroupedTieredPriceCadenceConverter + : JsonConverter +{ + public override NewPlanGroupedTieredPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanGroupedTieredPriceCadence.Annual, + "semi_annual" => NewPlanGroupedTieredPriceCadence.SemiAnnual, + "monthly" => NewPlanGroupedTieredPriceCadence.Monthly, + "quarterly" => NewPlanGroupedTieredPriceCadence.Quarterly, + "one_time" => NewPlanGroupedTieredPriceCadence.OneTime, + "custom" => NewPlanGroupedTieredPriceCadence.Custom, + _ => (NewPlanGroupedTieredPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedTieredPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedTieredPriceCadence.Annual => "annual", + NewPlanGroupedTieredPriceCadence.SemiAnnual => "semi_annual", + NewPlanGroupedTieredPriceCadence.Monthly => "monthly", + NewPlanGroupedTieredPriceCadence.Quarterly => "quarterly", + NewPlanGroupedTieredPriceCadence.OneTime => "one_time", + NewPlanGroupedTieredPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_tiered pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedTieredPriceGroupedTieredConfig, + NewPlanGroupedTieredPriceGroupedTieredConfigFromRaw + >) +)] +public sealed record class NewPlanGroupedTieredPriceGroupedTieredConfig : JsonModel +{ + /// + /// The billable metric property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Apply tiered pricing to each segment generated after grouping with the provided key + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public NewPlanGroupedTieredPriceGroupedTieredConfig() { } + + public NewPlanGroupedTieredPriceGroupedTieredConfig( + NewPlanGroupedTieredPriceGroupedTieredConfig newPlanGroupedTieredPriceGroupedTieredConfig + ) + : base(newPlanGroupedTieredPriceGroupedTieredConfig) { } + + public NewPlanGroupedTieredPriceGroupedTieredConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedTieredPriceGroupedTieredConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedTieredPriceGroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedTieredPriceGroupedTieredConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedTieredPriceGroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedTieredPriceGroupedTieredConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedTieredPriceGroupedTieredConfigTier, + NewPlanGroupedTieredPriceGroupedTieredConfigTierFromRaw + >) +)] +public sealed record class NewPlanGroupedTieredPriceGroupedTieredConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public NewPlanGroupedTieredPriceGroupedTieredConfigTier() { } + + public NewPlanGroupedTieredPriceGroupedTieredConfigTier( + NewPlanGroupedTieredPriceGroupedTieredConfigTier newPlanGroupedTieredPriceGroupedTieredConfigTier + ) + : base(newPlanGroupedTieredPriceGroupedTieredConfigTier) { } + + public NewPlanGroupedTieredPriceGroupedTieredConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedTieredPriceGroupedTieredConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedTieredPriceGroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedTieredPriceGroupedTieredConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedTieredPriceGroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedTieredPriceGroupedTieredConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanGroupedTieredPriceModelTypeConverter))] +public enum NewPlanGroupedTieredPriceModelType +{ + GroupedTiered, +} + +sealed class NewPlanGroupedTieredPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanGroupedTieredPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_tiered" => NewPlanGroupedTieredPriceModelType.GroupedTiered, + _ => (NewPlanGroupedTieredPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedTieredPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedTieredPriceModelType.GroupedTiered => "grouped_tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanGroupedTieredPriceConversionRateConfigConverter))] +public record class NewPlanGroupedTieredPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanGroupedTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedTieredPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedTieredPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedTieredPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanGroupedTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanGroupedTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedTieredPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanGroupedTieredPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanGroupedTieredPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanGroupedTieredPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanGroupedTieredPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedTieredPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanGroupedTieredPriceProperties/Cadence.cs deleted file mode 100644 index c2f5d73d..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedTieredPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 0b020c74..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanGroupedTieredPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedTieredPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 7c94cb32..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanGroupedTieredPriceProperties = Orb.Models.NewPlanGroupedTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedTieredPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanGroupedTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanGroupedTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ModelType.cs deleted file mode 100644 index 804c3b9d..00000000 --- a/src/Orb/Models/NewPlanGroupedTieredPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedTieredPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTiered = new("grouped_tiered"); - - readonly string _value = value; - - public enum Value - { - GroupedTiered, - } - - public Value Known() => - _value switch - { - "grouped_tiered" => Value.GroupedTiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPrice.cs b/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPrice.cs index 817a8e0a..5deec341 100644 --- a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPrice.cs +++ b/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPrice.cs @@ -1,62 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanGroupedWithMeteredMinimumPriceProperties = Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanGroupedWithMeteredMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedWithMeteredMinimumPrice, + NewPlanGroupedWithMeteredMinimumPriceFromRaw + >) +)] +public sealed record class NewPlanGroupedWithMeteredMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanGroupedWithMeteredMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedWithMeteredMinimumConfig + /// + /// Configuration for grouped_with_metered_minimum pricing + /// + public required NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig GroupedWithMeteredMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_with_metered_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_metered_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_with_metered_minimum_config"); - } - set - { - this.Properties["grouped_with_metered_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_metered_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_with_metered_minimum_config", value); } } /// @@ -64,35 +51,22 @@ public sealed record class NewPlanGroupedWithMeteredMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanGroupedWithMeteredMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -100,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,23 +228,15 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedWithMeteredMinimumConfig.Values) - { - _ = item; - } + this.GroupedWithMeteredMinimumConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -391,30 +251,732 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanGroupedWithMeteredMinimumPrice() { } + public NewPlanGroupedWithMeteredMinimumPrice( + NewPlanGroupedWithMeteredMinimumPrice newPlanGroupedWithMeteredMinimumPrice + ) + : base(newPlanGroupedWithMeteredMinimumPrice) { } + + public NewPlanGroupedWithMeteredMinimumPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanGroupedWithMeteredMinimumPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanGroupedWithMeteredMinimumPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanGroupedWithMeteredMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedWithMeteredMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedWithMeteredMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedWithMeteredMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanGroupedWithMeteredMinimumPriceCadenceConverter))] +public enum NewPlanGroupedWithMeteredMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanGroupedWithMeteredMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewPlanGroupedWithMeteredMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanGroupedWithMeteredMinimumPriceCadence.Annual, + "semi_annual" => NewPlanGroupedWithMeteredMinimumPriceCadence.SemiAnnual, + "monthly" => NewPlanGroupedWithMeteredMinimumPriceCadence.Monthly, + "quarterly" => NewPlanGroupedWithMeteredMinimumPriceCadence.Quarterly, + "one_time" => NewPlanGroupedWithMeteredMinimumPriceCadence.OneTime, + "custom" => NewPlanGroupedWithMeteredMinimumPriceCadence.Custom, + _ => (NewPlanGroupedWithMeteredMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedWithMeteredMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedWithMeteredMinimumPriceCadence.Annual => "annual", + NewPlanGroupedWithMeteredMinimumPriceCadence.SemiAnnual => "semi_annual", + NewPlanGroupedWithMeteredMinimumPriceCadence.Monthly => "monthly", + NewPlanGroupedWithMeteredMinimumPriceCadence.Quarterly => "quarterly", + NewPlanGroupedWithMeteredMinimumPriceCadence.OneTime => "one_time", + NewPlanGroupedWithMeteredMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_metered_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig, + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigFromRaw + >) +)] +public sealed record class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + : JsonModel +{ + /// + /// Used to partition the usage into groups. The minimum amount is applied to + /// each group. + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group per unit + /// + public required string MinimumUnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_unit_amount"); } + init { JsonModel.Set(this._rawData, "minimum_unit_amount", value); } + } + + /// + /// Used to determine the unit rate + /// + public required string PricingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_key"); } + init { JsonModel.Set(this._rawData, "pricing_key", value); } + } + + /// + /// Scale the unit rates by the scaling factor. + /// + public required IReadOnlyList ScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "scaling_factors"); + } + init { JsonModel.Set(this._rawData, "scaling_factors", value); } + } + + /// + /// Used to determine the unit rate scaling factor + /// + public required string ScalingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_key"); } + init { JsonModel.Set(this._rawData, "scaling_key", value); } + } + + /// + /// Apply per unit pricing to each pricing value. The minimum amount is applied + /// any unmatched usage. + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "unit_amounts"); + } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MinimumUnitAmount; + _ = this.PricingKey; + foreach (var item in this.ScalingFactors) + { + item.Validate(); + } + _ = this.ScalingKey; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig() { } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig( + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig newPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig + ) + : base(newPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig) { } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor, + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactorFromRaw + >) +)] +public sealed record class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor + : JsonModel +{ + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Scaling value + /// + public required string ScalingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_value"); } + init { JsonModel.Set(this._rawData, "scaling_value", value); } + } + + /// + public override void Validate() + { + _ = this.ScalingFactor; + _ = this.ScalingValue; + } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor() { } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor( + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor newPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor + ) + : base(newPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor) + { } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactorFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigScalingFactor.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a unit amount +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount, + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmountFromRaw + >) +)] +public sealed record class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount + : JsonModel +{ + /// + /// Pricing value + /// + public required string PricingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_value"); } + init { JsonModel.Set(this._rawData, "pricing_value", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.PricingValue; + _ = this.UnitAmount; + } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount() { } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount( + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount newPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount + ) + : base(newPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount) { } + + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmountFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanGroupedWithMeteredMinimumPriceGroupedWithMeteredMinimumConfigUnitAmount.FromRawUnchecked( + rawData + ); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanGroupedWithMeteredMinimumPriceModelTypeConverter))] +public enum NewPlanGroupedWithMeteredMinimumPriceModelType +{ + GroupedWithMeteredMinimum, +} + +sealed class NewPlanGroupedWithMeteredMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanGroupedWithMeteredMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_with_metered_minimum" => + NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + _ => (NewPlanGroupedWithMeteredMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedWithMeteredMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum => + "grouped_with_metered_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanGroupedWithMeteredMinimumPriceConversionRateConfigConverter))] +public record class NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanGroupedWithMeteredMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedWithMeteredMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 7705808b..00000000 --- a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 74a3aeb7..00000000 --- a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 910fbe89..00000000 --- a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanGroupedWithMeteredMinimumPriceProperties = Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ModelType.cs deleted file mode 100644 index 99e5c149..00000000 --- a/src/Orb/Models/NewPlanGroupedWithMeteredMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedWithMeteredMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithMeteredMinimum = new( - "grouped_with_metered_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithMeteredMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_metered_minimum" => Value.GroupedWithMeteredMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPrice.cs b/src/Orb/Models/NewPlanGroupedWithProratedMinimumPrice.cs index 434b738e..f80d73ab 100644 --- a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPrice.cs +++ b/src/Orb/Models/NewPlanGroupedWithProratedMinimumPrice.cs @@ -1,63 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanGroupedWithProratedMinimumPriceProperties = Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanGroupedWithProratedMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedWithProratedMinimumPrice, + NewPlanGroupedWithProratedMinimumPriceFromRaw + >) +)] +public sealed record class NewPlanGroupedWithProratedMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanGroupedWithProratedMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedWithProratedMinimumConfig + /// + /// Configuration for grouped_with_prorated_minimum pricing + /// + public required NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig GroupedWithProratedMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_with_prorated_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_prorated_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException("grouped_with_prorated_minimum_config"); - } - set - { - this.Properties["grouped_with_prorated_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_prorated_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_with_prorated_minimum_config", value); } } /// @@ -65,35 +51,22 @@ public sealed record class NewPlanGroupedWithProratedMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanGroupedWithProratedMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -101,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -117,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -178,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanGroupedWithProratedMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanGroupedWithProratedMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -238,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,23 +228,15 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedWithProratedMinimumConfig.Values) - { - _ = item; - } + this.GroupedWithProratedMinimumConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -392,32 +251,519 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanGroupedWithProratedMinimumPrice() { } -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanGroupedWithProratedMinimumPrice( - Generic::Dictionary properties + public NewPlanGroupedWithProratedMinimumPrice( + NewPlanGroupedWithProratedMinimumPrice newPlanGroupedWithProratedMinimumPrice ) + : base(newPlanGroupedWithProratedMinimumPrice) { } + + public NewPlanGroupedWithProratedMinimumPrice(IReadOnlyDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedWithProratedMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanGroupedWithProratedMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedWithProratedMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedWithProratedMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanGroupedWithProratedMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanGroupedWithProratedMinimumPriceCadenceConverter))] +public enum NewPlanGroupedWithProratedMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanGroupedWithProratedMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewPlanGroupedWithProratedMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanGroupedWithProratedMinimumPriceCadence.Annual, + "semi_annual" => NewPlanGroupedWithProratedMinimumPriceCadence.SemiAnnual, + "monthly" => NewPlanGroupedWithProratedMinimumPriceCadence.Monthly, + "quarterly" => NewPlanGroupedWithProratedMinimumPriceCadence.Quarterly, + "one_time" => NewPlanGroupedWithProratedMinimumPriceCadence.OneTime, + "custom" => NewPlanGroupedWithProratedMinimumPriceCadence.Custom, + _ => (NewPlanGroupedWithProratedMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedWithProratedMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedWithProratedMinimumPriceCadence.Annual => "annual", + NewPlanGroupedWithProratedMinimumPriceCadence.SemiAnnual => "semi_annual", + NewPlanGroupedWithProratedMinimumPriceCadence.Monthly => "monthly", + NewPlanGroupedWithProratedMinimumPriceCadence.Quarterly => "quarterly", + NewPlanGroupedWithProratedMinimumPriceCadence.OneTime => "one_time", + NewPlanGroupedWithProratedMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_prorated_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig, + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfigFromRaw + >) +)] +public sealed record class NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + : JsonModel +{ + /// + /// How to determine the groups that should each have a minimum + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group + /// + public required string Minimum + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + /// + /// The amount to charge per unit + /// + public required string UnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rate"); } + init { JsonModel.Set(this._rawData, "unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.Minimum; + _ = this.UnitRate; + } + + public NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig() { } + + public NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig( + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig newPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig + ) + : base(newPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig) { } + + public NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanGroupedWithProratedMinimumPriceGroupedWithProratedMinimumConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanGroupedWithProratedMinimumPriceModelTypeConverter))] +public enum NewPlanGroupedWithProratedMinimumPriceModelType +{ + GroupedWithProratedMinimum, +} + +sealed class NewPlanGroupedWithProratedMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanGroupedWithProratedMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_with_prorated_minimum" => + NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + _ => (NewPlanGroupedWithProratedMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedWithProratedMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum => + "grouped_with_prorated_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanGroupedWithProratedMinimumPriceConversionRateConfigConverter))] +public record class NewPlanGroupedWithProratedMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanGroupedWithProratedMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedWithProratedMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanGroupedWithProratedMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedWithProratedMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedWithProratedMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanGroupedWithProratedMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanGroupedWithProratedMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanGroupedWithProratedMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanGroupedWithProratedMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanGroupedWithProratedMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanGroupedWithProratedMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanGroupedWithProratedMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanGroupedWithProratedMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/Cadence.cs deleted file mode 100644 index b6e23904..00000000 --- a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 19ff2e48..00000000 --- a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f38d4f4e..00000000 --- a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanGroupedWithProratedMinimumPriceProperties = Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanGroupedWithProratedMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanGroupedWithProratedMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ModelType.cs deleted file mode 100644 index 8d40bad1..00000000 --- a/src/Orb/Models/NewPlanGroupedWithProratedMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanGroupedWithProratedMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithProratedMinimum = new( - "grouped_with_prorated_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithProratedMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_prorated_minimum" => Value.GroupedWithProratedMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMatrixPrice.cs b/src/Orb/Models/NewPlanMatrixPrice.cs index 24c66f60..27942c33 100644 --- a/src/Orb/Models/NewPlanMatrixPrice.cs +++ b/src/Orb/Models/NewPlanMatrixPrice.cs @@ -1,33 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanMatrixPriceProperties = Orb.Models.NewPlanMatrixPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanMatrixPrice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewPlanMatrixPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanMatrixPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -35,51 +32,32 @@ public sealed record class NewPlanMatrixPrice : Orb::ModelBase, Orb::IFromRaw public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } + /// + /// Configuration for matrix pricing + /// public required MatrixConfig MatrixConfig { - get - { - if (!this.Properties.TryGetValue("matrix_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_config"); - } - set { this.Properties["matrix_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "matrix_config"); } + init { JsonModel.Set(this._rawData, "matrix_config", value); } } - public required NewPlanMatrixPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -87,15 +65,8 @@ public required MatrixConfig MatrixConfig /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -103,60 +74,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -164,57 +109,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanMatrixPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanMatrixPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -224,21 +145,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -246,17 +158,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -264,19 +167,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -284,19 +176,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -307,21 +188,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -329,16 +201,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -347,16 +219,11 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -375,30 +242,419 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanMatrixPrice() { } + public NewPlanMatrixPrice(NewPlanMatrixPrice newPlanMatrixPrice) + : base(newPlanMatrixPrice) { } + + public NewPlanMatrixPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanMatrixPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanMatrixPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanMatrixPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMatrixPriceFromRaw : IFromRawJson +{ + /// + public NewPlanMatrixPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + NewPlanMatrixPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanMatrixPriceCadenceConverter))] +public enum NewPlanMatrixPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanMatrixPriceCadenceConverter : JsonConverter +{ + public override NewPlanMatrixPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanMatrixPriceCadence.Annual, + "semi_annual" => NewPlanMatrixPriceCadence.SemiAnnual, + "monthly" => NewPlanMatrixPriceCadence.Monthly, + "quarterly" => NewPlanMatrixPriceCadence.Quarterly, + "one_time" => NewPlanMatrixPriceCadence.OneTime, + "custom" => NewPlanMatrixPriceCadence.Custom, + _ => (NewPlanMatrixPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMatrixPriceCadence.Annual => "annual", + NewPlanMatrixPriceCadence.SemiAnnual => "semi_annual", + NewPlanMatrixPriceCadence.Monthly => "monthly", + NewPlanMatrixPriceCadence.Quarterly => "quarterly", + NewPlanMatrixPriceCadence.OneTime => "one_time", + NewPlanMatrixPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanMatrixPriceModelTypeConverter))] +public enum NewPlanMatrixPriceModelType +{ + Matrix, +} + +sealed class NewPlanMatrixPriceModelTypeConverter : JsonConverter +{ + public override NewPlanMatrixPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix" => NewPlanMatrixPriceModelType.Matrix, + _ => (NewPlanMatrixPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMatrixPriceModelType.Matrix => "matrix", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanMatrixPriceConversionRateConfigConverter))] +public record class NewPlanMatrixPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanMatrixPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMatrixPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMatrixPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanMatrixPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanMatrixPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanMatrixPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanMatrixPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanMatrixPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanMatrixPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanMatrixPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanMatrixPriceProperties/Cadence.cs deleted file mode 100644 index 14867bd0..00000000 --- a/src/Orb/Models/NewPlanMatrixPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMatrixPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMatrixPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanMatrixPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 3f2a4be4..00000000 --- a/src/Orb/Models/NewPlanMatrixPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanMatrixPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMatrixPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanMatrixPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanMatrixPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 1c5a7af9..00000000 --- a/src/Orb/Models/NewPlanMatrixPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanMatrixPriceProperties = Orb.Models.NewPlanMatrixPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMatrixPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanMatrixPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanMatrixPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanMatrixPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanMatrixPriceProperties/ModelType.cs deleted file mode 100644 index 3dc75dbf..00000000 --- a/src/Orb/Models/NewPlanMatrixPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMatrixPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Matrix = new("matrix"); - - readonly string _value = value; - - public enum Value - { - Matrix, - } - - public Value Known() => - _value switch - { - "matrix" => Value.Matrix, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMatrixWithAllocationPrice.cs b/src/Orb/Models/NewPlanMatrixWithAllocationPrice.cs index 46d83090..a8c46ccb 100644 --- a/src/Orb/Models/NewPlanMatrixWithAllocationPrice.cs +++ b/src/Orb/Models/NewPlanMatrixWithAllocationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanMatrixWithAllocationPriceProperties = Orb.Models.NewPlanMatrixWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanMatrixWithAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMatrixWithAllocationPrice, + NewPlanMatrixWithAllocationPriceFromRaw + >) +)] +public sealed record class NewPlanMatrixWithAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanMatrixWithAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,60 +36,37 @@ public sealed record class NewPlanMatrixWithAllocationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } + /// + /// Configuration for matrix_with_allocation pricing + /// public required MatrixWithAllocationConfig MatrixWithAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "matrix_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_with_allocation_config"); - } - set - { - this.Properties["matrix_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_allocation_config" + ); } + init { JsonModel.Set(this._rawData, "matrix_with_allocation_config", value); } } - public required NewPlanMatrixWithAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -99,15 +74,8 @@ public required MatrixWithAllocationConfig MatrixWithAllocationConfig /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -115,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -176,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanMatrixWithAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanMatrixWithAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -236,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -258,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -276,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -296,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -319,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -341,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -359,16 +228,11 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -387,30 +251,426 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanMatrixWithAllocationPrice() { } + public NewPlanMatrixWithAllocationPrice( + NewPlanMatrixWithAllocationPrice newPlanMatrixWithAllocationPrice + ) + : base(newPlanMatrixWithAllocationPrice) { } + + public NewPlanMatrixWithAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanMatrixWithAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanMatrixWithAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanMatrixWithAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMatrixWithAllocationPriceFromRaw : IFromRawJson +{ + /// + public NewPlanMatrixWithAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMatrixWithAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanMatrixWithAllocationPriceCadenceConverter))] +public enum NewPlanMatrixWithAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanMatrixWithAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewPlanMatrixWithAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanMatrixWithAllocationPriceCadence.Annual, + "semi_annual" => NewPlanMatrixWithAllocationPriceCadence.SemiAnnual, + "monthly" => NewPlanMatrixWithAllocationPriceCadence.Monthly, + "quarterly" => NewPlanMatrixWithAllocationPriceCadence.Quarterly, + "one_time" => NewPlanMatrixWithAllocationPriceCadence.OneTime, + "custom" => NewPlanMatrixWithAllocationPriceCadence.Custom, + _ => (NewPlanMatrixWithAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixWithAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMatrixWithAllocationPriceCadence.Annual => "annual", + NewPlanMatrixWithAllocationPriceCadence.SemiAnnual => "semi_annual", + NewPlanMatrixWithAllocationPriceCadence.Monthly => "monthly", + NewPlanMatrixWithAllocationPriceCadence.Quarterly => "quarterly", + NewPlanMatrixWithAllocationPriceCadence.OneTime => "one_time", + NewPlanMatrixWithAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanMatrixWithAllocationPriceModelTypeConverter))] +public enum NewPlanMatrixWithAllocationPriceModelType +{ + MatrixWithAllocation, +} + +sealed class NewPlanMatrixWithAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanMatrixWithAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix_with_allocation" => + NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation, + _ => (NewPlanMatrixWithAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixWithAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMatrixWithAllocationPriceModelType.MatrixWithAllocation => + "matrix_with_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanMatrixWithAllocationPriceConversionRateConfigConverter))] +public record class NewPlanMatrixWithAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanMatrixWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMatrixWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMatrixWithAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixWithAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixWithAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanMatrixWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanMatrixWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixWithAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanMatrixWithAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanMatrixWithAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanMatrixWithAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanMatrixWithAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixWithAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 403a4160..00000000 --- a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMatrixWithAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 1b9ad410..00000000 --- a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanMatrixWithAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMatrixWithAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 903f2489..00000000 --- a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanMatrixWithAllocationPriceProperties = Orb.Models.NewPlanMatrixWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMatrixWithAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanMatrixWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanMatrixWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 20011896..00000000 --- a/src/Orb/Models/NewPlanMatrixWithAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMatrixWithAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithAllocation = new("matrix_with_allocation"); - - readonly string _value = value; - - public enum Value - { - MatrixWithAllocation, - } - - public Value Known() => - _value switch - { - "matrix_with_allocation" => Value.MatrixWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMatrixWithDisplayNamePrice.cs b/src/Orb/Models/NewPlanMatrixWithDisplayNamePrice.cs index d8db5db6..623bad3d 100644 --- a/src/Orb/Models/NewPlanMatrixWithDisplayNamePrice.cs +++ b/src/Orb/Models/NewPlanMatrixWithDisplayNamePrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanMatrixWithDisplayNamePriceProperties = Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanMatrixWithDisplayNamePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMatrixWithDisplayNamePrice, + NewPlanMatrixWithDisplayNamePriceFromRaw + >) +)] +public sealed record class NewPlanMatrixWithDisplayNamePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanMatrixWithDisplayNamePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,61 +36,37 @@ public sealed record class NewPlanMatrixWithDisplayNamePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Generic::Dictionary MatrixWithDisplayNameConfig + /// + /// Configuration for matrix_with_display_name pricing + /// + public required NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig MatrixWithDisplayNameConfig { get { - if ( - !this.Properties.TryGetValue( - "matrix_with_display_name_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_display_name_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("matrix_with_display_name_config"); - } - set - { - this.Properties["matrix_with_display_name_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_display_name_config" + ); } + init { JsonModel.Set(this._rawData, "matrix_with_display_name_config", value); } } - public required NewPlanMatrixWithDisplayNamePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -100,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanMatrixWithDisplayNamePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanMatrixWithDisplayNamePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,24 +228,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; - foreach (var item in this.MatrixWithDisplayNameConfig.Values) - { - _ = item; - } + this.MatrixWithDisplayNameConfig.Validate(); this.ModelType.Validate(); _ = this.Name; _ = this.BillableMetricID; @@ -391,30 +251,604 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanMatrixWithDisplayNamePrice() { } + public NewPlanMatrixWithDisplayNamePrice( + NewPlanMatrixWithDisplayNamePrice newPlanMatrixWithDisplayNamePrice + ) + : base(newPlanMatrixWithDisplayNamePrice) { } + + public NewPlanMatrixWithDisplayNamePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanMatrixWithDisplayNamePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanMatrixWithDisplayNamePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanMatrixWithDisplayNamePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMatrixWithDisplayNamePriceFromRaw : IFromRawJson +{ + /// + public NewPlanMatrixWithDisplayNamePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMatrixWithDisplayNamePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanMatrixWithDisplayNamePriceCadenceConverter))] +public enum NewPlanMatrixWithDisplayNamePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanMatrixWithDisplayNamePriceCadenceConverter + : JsonConverter +{ + public override NewPlanMatrixWithDisplayNamePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanMatrixWithDisplayNamePriceCadence.Annual, + "semi_annual" => NewPlanMatrixWithDisplayNamePriceCadence.SemiAnnual, + "monthly" => NewPlanMatrixWithDisplayNamePriceCadence.Monthly, + "quarterly" => NewPlanMatrixWithDisplayNamePriceCadence.Quarterly, + "one_time" => NewPlanMatrixWithDisplayNamePriceCadence.OneTime, + "custom" => NewPlanMatrixWithDisplayNamePriceCadence.Custom, + _ => (NewPlanMatrixWithDisplayNamePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixWithDisplayNamePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMatrixWithDisplayNamePriceCadence.Annual => "annual", + NewPlanMatrixWithDisplayNamePriceCadence.SemiAnnual => "semi_annual", + NewPlanMatrixWithDisplayNamePriceCadence.Monthly => "monthly", + NewPlanMatrixWithDisplayNamePriceCadence.Quarterly => "quarterly", + NewPlanMatrixWithDisplayNamePriceCadence.OneTime => "one_time", + NewPlanMatrixWithDisplayNamePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for matrix_with_display_name pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig, + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigFromRaw + >) +)] +public sealed record class NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string Dimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension"); } + init { JsonModel.Set(this._rawData, "dimension", value); } + } + + /// + /// Apply per unit pricing to each dimension value + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "unit_amounts"); + } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } + } + + /// + public override void Validate() + { + _ = this.Dimension; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig() { } + + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig( + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig newPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig + ) + : base(newPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig) { } + + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a unit amount item +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount, + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmountFromRaw + >) +)] +public sealed record class NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount + : JsonModel +{ + /// + /// The dimension value + /// + public required string DimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension_value"); } + init { JsonModel.Set(this._rawData, "dimension_value", value); } + } + + /// + /// Display name for this dimension value + /// + public required string DisplayName + { + get { return JsonModel.GetNotNullClass(this.RawData, "display_name"); } + init { JsonModel.Set(this._rawData, "display_name", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.DimensionValue; + _ = this.DisplayName; + _ = this.UnitAmount; + } + + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount() { } + + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount( + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount newPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount + ) + : base(newPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount) { } + + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmountFromRaw + : IFromRawJson +{ + /// + public NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanMatrixWithDisplayNamePriceMatrixWithDisplayNameConfigUnitAmount.FromRawUnchecked( + rawData + ); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanMatrixWithDisplayNamePriceModelTypeConverter))] +public enum NewPlanMatrixWithDisplayNamePriceModelType +{ + MatrixWithDisplayName, +} + +sealed class NewPlanMatrixWithDisplayNamePriceModelTypeConverter + : JsonConverter +{ + public override NewPlanMatrixWithDisplayNamePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix_with_display_name" => + NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + _ => (NewPlanMatrixWithDisplayNamePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixWithDisplayNamePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName => + "matrix_with_display_name", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanMatrixWithDisplayNamePriceConversionRateConfigConverter))] +public record class NewPlanMatrixWithDisplayNamePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanMatrixWithDisplayNamePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMatrixWithDisplayNamePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMatrixWithDisplayNamePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixWithDisplayNamePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixWithDisplayNamePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanMatrixWithDisplayNamePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanMatrixWithDisplayNamePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMatrixWithDisplayNamePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanMatrixWithDisplayNamePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanMatrixWithDisplayNamePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanMatrixWithDisplayNamePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanMatrixWithDisplayNamePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMatrixWithDisplayNamePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/Cadence.cs b/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/Cadence.cs deleted file mode 100644 index 09511979..00000000 --- a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 42005079..00000000 --- a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 678946e1..00000000 --- a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanMatrixWithDisplayNamePriceProperties = Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanMatrixWithDisplayNamePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanMatrixWithDisplayNamePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ModelType.cs b/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ModelType.cs deleted file mode 100644 index ce34bb41..00000000 --- a/src/Orb/Models/NewPlanMatrixWithDisplayNamePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMatrixWithDisplayNamePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithDisplayName = new("matrix_with_display_name"); - - readonly string _value = value; - - public enum Value - { - MatrixWithDisplayName, - } - - public Value Known() => - _value switch - { - "matrix_with_display_name" => Value.MatrixWithDisplayName, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMaxGroupTieredPackagePrice.cs b/src/Orb/Models/NewPlanMaxGroupTieredPackagePrice.cs index de1d13b1..429f10c4 100644 --- a/src/Orb/Models/NewPlanMaxGroupTieredPackagePrice.cs +++ b/src/Orb/Models/NewPlanMaxGroupTieredPackagePrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanMaxGroupTieredPackagePriceProperties = Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanMaxGroupTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMaxGroupTieredPackagePrice, + NewPlanMaxGroupTieredPackagePriceFromRaw + >) +)] +public sealed record class NewPlanMaxGroupTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanMaxGroupTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,61 +36,37 @@ public sealed record class NewPlanMaxGroupTieredPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Generic::Dictionary MaxGroupTieredPackageConfig + /// + /// Configuration for max_group_tiered_package pricing + /// + public required NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig MaxGroupTieredPackageConfig { get { - if ( - !this.Properties.TryGetValue( - "max_group_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "max_group_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("max_group_tiered_package_config"); - } - set - { - this.Properties["max_group_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "max_group_tiered_package_config" + ); } + init { JsonModel.Set(this._rawData, "max_group_tiered_package_config", value); } } - public required NewPlanMaxGroupTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -100,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanMaxGroupTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanMaxGroupTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,24 +228,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; - foreach (var item in this.MaxGroupTieredPackageConfig.Values) - { - _ = item; - } + this.MaxGroupTieredPackageConfig.Validate(); this.ModelType.Validate(); _ = this.Name; _ = this.BillableMetricID; @@ -391,30 +251,601 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanMaxGroupTieredPackagePrice() { } + public NewPlanMaxGroupTieredPackagePrice( + NewPlanMaxGroupTieredPackagePrice newPlanMaxGroupTieredPackagePrice + ) + : base(newPlanMaxGroupTieredPackagePrice) { } + + public NewPlanMaxGroupTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanMaxGroupTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanMaxGroupTieredPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanMaxGroupTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMaxGroupTieredPackagePriceFromRaw : IFromRawJson +{ + /// + public NewPlanMaxGroupTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMaxGroupTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanMaxGroupTieredPackagePriceCadenceConverter))] +public enum NewPlanMaxGroupTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanMaxGroupTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewPlanMaxGroupTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanMaxGroupTieredPackagePriceCadence.Annual, + "semi_annual" => NewPlanMaxGroupTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewPlanMaxGroupTieredPackagePriceCadence.Monthly, + "quarterly" => NewPlanMaxGroupTieredPackagePriceCadence.Quarterly, + "one_time" => NewPlanMaxGroupTieredPackagePriceCadence.OneTime, + "custom" => NewPlanMaxGroupTieredPackagePriceCadence.Custom, + _ => (NewPlanMaxGroupTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMaxGroupTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMaxGroupTieredPackagePriceCadence.Annual => "annual", + NewPlanMaxGroupTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewPlanMaxGroupTieredPackagePriceCadence.Monthly => "monthly", + NewPlanMaxGroupTieredPackagePriceCadence.Quarterly => "quarterly", + NewPlanMaxGroupTieredPackagePriceCadence.OneTime => "one_time", + NewPlanMaxGroupTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for max_group_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig, + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigFromRaw + >) +)] +public sealed record class NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering the group with the highest value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing to the largest group after grouping with the provided key. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig() { } + + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig( + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig newPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig + ) + : base(newPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig) { } + + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier, + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTierFromRaw + >) +)] +public sealed record class NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier + : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier() { } + + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier( + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier newPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier + ) + : base(newPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier) { } + + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMaxGroupTieredPackagePriceMaxGroupTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanMaxGroupTieredPackagePriceModelTypeConverter))] +public enum NewPlanMaxGroupTieredPackagePriceModelType +{ + MaxGroupTieredPackage, +} + +sealed class NewPlanMaxGroupTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewPlanMaxGroupTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "max_group_tiered_package" => + NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + _ => (NewPlanMaxGroupTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMaxGroupTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage => + "max_group_tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanMaxGroupTieredPackagePriceConversionRateConfigConverter))] +public record class NewPlanMaxGroupTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanMaxGroupTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMaxGroupTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMaxGroupTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMaxGroupTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMaxGroupTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanMaxGroupTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanMaxGroupTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMaxGroupTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanMaxGroupTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanMaxGroupTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanMaxGroupTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanMaxGroupTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMaxGroupTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index a1cb0034..00000000 --- a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 2e58ffe7..00000000 --- a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 9d02726c..00000000 --- a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanMaxGroupTieredPackagePriceProperties = Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanMaxGroupTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanMaxGroupTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index 760c05f8..00000000 --- a/src/Orb/Models/NewPlanMaxGroupTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanMaxGroupTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MaxGroupTieredPackage = new("max_group_tiered_package"); - - readonly string _value = value; - - public enum Value - { - MaxGroupTieredPackage, - } - - public Value Known() => - _value switch - { - "max_group_tiered_package" => Value.MaxGroupTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanMinimumCompositePrice.cs b/src/Orb/Models/NewPlanMinimumCompositePrice.cs new file mode 100644 index 00000000..ff0f01ea --- /dev/null +++ b/src/Orb/Models/NewPlanMinimumCompositePrice.cs @@ -0,0 +1,761 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models; + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanMinimumCompositePrice : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// Configuration for minimum pricing + /// + public required NewPlanMinimumCompositePriceMinimumConfig MinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "minimum_config", value); } + } + + /// + /// The pricing model type + /// + public required ApiEnum ModelType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); + } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public NewPlanMinimumCompositePriceConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + this.MinimumConfig.Validate(); + this.ModelType.Validate(); + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewPlanMinimumCompositePrice() { } + + public NewPlanMinimumCompositePrice(NewPlanMinimumCompositePrice newPlanMinimumCompositePrice) + : base(newPlanMinimumCompositePrice) { } + + public NewPlanMinimumCompositePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanMinimumCompositePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanMinimumCompositePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanMinimumCompositePriceFromRaw : IFromRawJson +{ + /// + public NewPlanMinimumCompositePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMinimumCompositePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanMinimumCompositePriceCadenceConverter))] +public enum NewPlanMinimumCompositePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanMinimumCompositePriceCadenceConverter + : JsonConverter +{ + public override NewPlanMinimumCompositePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanMinimumCompositePriceCadence.Annual, + "semi_annual" => NewPlanMinimumCompositePriceCadence.SemiAnnual, + "monthly" => NewPlanMinimumCompositePriceCadence.Monthly, + "quarterly" => NewPlanMinimumCompositePriceCadence.Quarterly, + "one_time" => NewPlanMinimumCompositePriceCadence.OneTime, + "custom" => NewPlanMinimumCompositePriceCadence.Custom, + _ => (NewPlanMinimumCompositePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMinimumCompositePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMinimumCompositePriceCadence.Annual => "annual", + NewPlanMinimumCompositePriceCadence.SemiAnnual => "semi_annual", + NewPlanMinimumCompositePriceCadence.Monthly => "monthly", + NewPlanMinimumCompositePriceCadence.Quarterly => "quarterly", + NewPlanMinimumCompositePriceCadence.OneTime => "one_time", + NewPlanMinimumCompositePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanMinimumCompositePriceMinimumConfig, + NewPlanMinimumCompositePriceMinimumConfigFromRaw + >) +)] +public sealed record class NewPlanMinimumCompositePriceMinimumConfig : JsonModel +{ + /// + /// The minimum amount to apply + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// If true, subtotals from this price are prorated based on the service period + /// + public bool? Prorated + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorated"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorated", value); + } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.Prorated; + } + + public NewPlanMinimumCompositePriceMinimumConfig() { } + + public NewPlanMinimumCompositePriceMinimumConfig( + NewPlanMinimumCompositePriceMinimumConfig newPlanMinimumCompositePriceMinimumConfig + ) + : base(newPlanMinimumCompositePriceMinimumConfig) { } + + public NewPlanMinimumCompositePriceMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanMinimumCompositePriceMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanMinimumCompositePriceMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewPlanMinimumCompositePriceMinimumConfig(string minimumAmount) + : this() + { + this.MinimumAmount = minimumAmount; + } +} + +class NewPlanMinimumCompositePriceMinimumConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanMinimumCompositePriceMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanMinimumCompositePriceMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanMinimumCompositePriceModelTypeConverter))] +public enum NewPlanMinimumCompositePriceModelType +{ + Minimum, +} + +sealed class NewPlanMinimumCompositePriceModelTypeConverter + : JsonConverter +{ + public override NewPlanMinimumCompositePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "minimum" => NewPlanMinimumCompositePriceModelType.Minimum, + _ => (NewPlanMinimumCompositePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMinimumCompositePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanMinimumCompositePriceModelType.Minimum => "minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanMinimumCompositePriceConversionRateConfigConverter))] +public record class NewPlanMinimumCompositePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanMinimumCompositePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMinimumCompositePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanMinimumCompositePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMinimumCompositePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMinimumCompositePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanMinimumCompositePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanMinimumCompositePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanMinimumCompositePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanMinimumCompositePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanMinimumCompositePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanMinimumCompositePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanMinimumCompositePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanMinimumCompositePriceConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Models/NewPlanPackagePrice.cs b/src/Orb/Models/NewPlanPackagePrice.cs index b2afb059..bde6eac7 100644 --- a/src/Orb/Models/NewPlanPackagePrice.cs +++ b/src/Orb/Models/NewPlanPackagePrice.cs @@ -1,33 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanPackagePriceProperties = Orb.Models.NewPlanPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanPackagePrice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewPlanPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -35,35 +32,23 @@ public sealed record class NewPlanPackagePrice : Orb::ModelBase, Orb::IFromRaw public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -71,31 +56,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// + /// Configuration for package pricing + /// public required PackageConfig PackageConfig { - get - { - if (!this.Properties.TryGetValue("package_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("package_config"); - } - set { this.Properties["package_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "package_config"); } + init { JsonModel.Set(this._rawData, "package_config", value); } } /// @@ -103,60 +74,34 @@ public required PackageConfig PackageConfig /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -164,57 +109,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -224,21 +145,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -246,17 +158,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -264,19 +167,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -284,19 +176,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -307,21 +188,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -329,16 +201,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -347,16 +219,11 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -375,30 +242,419 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanPackagePrice() { } + public NewPlanPackagePrice(NewPlanPackagePrice newPlanPackagePrice) + : base(newPlanPackagePrice) { } + + public NewPlanPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanPackagePriceFromRaw : IFromRawJson +{ + /// + public NewPlanPackagePrice FromRawUnchecked(IReadOnlyDictionary rawData) => + NewPlanPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanPackagePriceCadenceConverter))] +public enum NewPlanPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanPackagePriceCadenceConverter : JsonConverter +{ + public override NewPlanPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanPackagePriceCadence.Annual, + "semi_annual" => NewPlanPackagePriceCadence.SemiAnnual, + "monthly" => NewPlanPackagePriceCadence.Monthly, + "quarterly" => NewPlanPackagePriceCadence.Quarterly, + "one_time" => NewPlanPackagePriceCadence.OneTime, + "custom" => NewPlanPackagePriceCadence.Custom, + _ => (NewPlanPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanPackagePriceCadence.Annual => "annual", + NewPlanPackagePriceCadence.SemiAnnual => "semi_annual", + NewPlanPackagePriceCadence.Monthly => "monthly", + NewPlanPackagePriceCadence.Quarterly => "quarterly", + NewPlanPackagePriceCadence.OneTime => "one_time", + NewPlanPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanPackagePriceModelTypeConverter))] +public enum NewPlanPackagePriceModelType +{ + Package, +} + +sealed class NewPlanPackagePriceModelTypeConverter : JsonConverter +{ + public override NewPlanPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "package" => NewPlanPackagePriceModelType.Package, + _ => (NewPlanPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanPackagePriceModelType.Package => "package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanPackagePriceConversionRateConfigConverter))] +public record class NewPlanPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewPlanPackagePriceProperties/Cadence.cs deleted file mode 100644 index 11fa4bba..00000000 --- a/src/Orb/Models/NewPlanPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index bc06220b..00000000 --- a/src/Orb/Models/NewPlanPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 61870215..00000000 --- a/src/Orb/Models/NewPlanPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanPackagePriceProperties = Orb.Models.NewPlanPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewPlanPackagePriceProperties/ModelType.cs deleted file mode 100644 index 2fff8865..00000000 --- a/src/Orb/Models/NewPlanPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Package = new("package"); - - readonly string _value = value; - - public enum Value - { - Package, - } - - public Value Known() => - _value switch - { - "package" => Value.Package, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanPackageWithAllocationPrice.cs b/src/Orb/Models/NewPlanPackageWithAllocationPrice.cs index 424168e4..621bd478 100644 --- a/src/Orb/Models/NewPlanPackageWithAllocationPrice.cs +++ b/src/Orb/Models/NewPlanPackageWithAllocationPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanPackageWithAllocationPriceProperties = Orb.Models.NewPlanPackageWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanPackageWithAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanPackageWithAllocationPrice, + NewPlanPackageWithAllocationPriceFromRaw + >) +)] +public sealed record class NewPlanPackageWithAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanPackageWithAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +36,22 @@ public sealed record class NewPlanPackageWithAllocationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanPackageWithAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,41 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary PackageWithAllocationConfig + /// + /// Configuration for package_with_allocation pricing + /// + public required NewPlanPackageWithAllocationPricePackageWithAllocationConfig PackageWithAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "package_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "package_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("package_with_allocation_config"); - } - set - { - this.Properties["package_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "package_with_allocation_config" + ); } + init { JsonModel.Set(this._rawData, "package_with_allocation_config", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanPackageWithAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanPackageWithAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,26 +228,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.PackageWithAllocationConfig.Values) - { - _ = item; - } + this.PackageWithAllocationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -391,30 +251,514 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanPackageWithAllocationPrice() { } + public NewPlanPackageWithAllocationPrice( + NewPlanPackageWithAllocationPrice newPlanPackageWithAllocationPrice + ) + : base(newPlanPackageWithAllocationPrice) { } + + public NewPlanPackageWithAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanPackageWithAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanPackageWithAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanPackageWithAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanPackageWithAllocationPriceFromRaw : IFromRawJson +{ + /// + public NewPlanPackageWithAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanPackageWithAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanPackageWithAllocationPriceCadenceConverter))] +public enum NewPlanPackageWithAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanPackageWithAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewPlanPackageWithAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanPackageWithAllocationPriceCadence.Annual, + "semi_annual" => NewPlanPackageWithAllocationPriceCadence.SemiAnnual, + "monthly" => NewPlanPackageWithAllocationPriceCadence.Monthly, + "quarterly" => NewPlanPackageWithAllocationPriceCadence.Quarterly, + "one_time" => NewPlanPackageWithAllocationPriceCadence.OneTime, + "custom" => NewPlanPackageWithAllocationPriceCadence.Custom, + _ => (NewPlanPackageWithAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanPackageWithAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanPackageWithAllocationPriceCadence.Annual => "annual", + NewPlanPackageWithAllocationPriceCadence.SemiAnnual => "semi_annual", + NewPlanPackageWithAllocationPriceCadence.Monthly => "monthly", + NewPlanPackageWithAllocationPriceCadence.Quarterly => "quarterly", + NewPlanPackageWithAllocationPriceCadence.OneTime => "one_time", + NewPlanPackageWithAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanPackageWithAllocationPriceModelTypeConverter))] +public enum NewPlanPackageWithAllocationPriceModelType +{ + PackageWithAllocation, +} + +sealed class NewPlanPackageWithAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanPackageWithAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "package_with_allocation" => + NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation, + _ => (NewPlanPackageWithAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanPackageWithAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanPackageWithAllocationPriceModelType.PackageWithAllocation => + "package_with_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for package_with_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanPackageWithAllocationPricePackageWithAllocationConfig, + NewPlanPackageWithAllocationPricePackageWithAllocationConfigFromRaw + >) +)] +public sealed record class NewPlanPackageWithAllocationPricePackageWithAllocationConfig : JsonModel +{ + /// + /// Usage allocation + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// Price per package + /// + public required string PackageAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_amount"); } + init { JsonModel.Set(this._rawData, "package_amount", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.PackageAmount; + _ = this.PackageSize; + } + + public NewPlanPackageWithAllocationPricePackageWithAllocationConfig() { } + + public NewPlanPackageWithAllocationPricePackageWithAllocationConfig( + NewPlanPackageWithAllocationPricePackageWithAllocationConfig newPlanPackageWithAllocationPricePackageWithAllocationConfig + ) + : base(newPlanPackageWithAllocationPricePackageWithAllocationConfig) { } + + public NewPlanPackageWithAllocationPricePackageWithAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanPackageWithAllocationPricePackageWithAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanPackageWithAllocationPricePackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanPackageWithAllocationPricePackageWithAllocationConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanPackageWithAllocationPricePackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanPackageWithAllocationPricePackageWithAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewPlanPackageWithAllocationPriceConversionRateConfigConverter))] +public record class NewPlanPackageWithAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanPackageWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanPackageWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanPackageWithAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanPackageWithAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanPackageWithAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanPackageWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanPackageWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanPackageWithAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanPackageWithAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanPackageWithAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanPackageWithAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanPackageWithAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanPackageWithAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 70a3296f..00000000 --- a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanPackageWithAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index c21a0d18..00000000 --- a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanPackageWithAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanPackageWithAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index d47446e7..00000000 --- a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanPackageWithAllocationPriceProperties = Orb.Models.NewPlanPackageWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanPackageWithAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanPackageWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanPackageWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 63052b48..00000000 --- a/src/Orb/Models/NewPlanPackageWithAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanPackageWithAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType PackageWithAllocation = new("package_with_allocation"); - - readonly string _value = value; - - public enum Value - { - PackageWithAllocation, - } - - public Value Known() => - _value switch - { - "package_with_allocation" => Value.PackageWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPrice.cs b/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPrice.cs index 61a62e57..37ac4fca 100644 --- a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPrice.cs +++ b/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanScalableMatrixWithTieredPricingPriceProperties = Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithTieredPricingPrice, + NewPlanScalableMatrixWithTieredPricingPriceFromRaw + >) )] -public sealed record class NewPlanScalableMatrixWithTieredPricingPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewPlanScalableMatrixWithTieredPricingPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanScalableMatrixWithTieredPricingPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,35 +36,22 @@ public sealed record class NewPlanScalableMatrixWithTieredPricingPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanScalableMatrixWithTieredPricingPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -76,47 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithTieredPricingConfig + /// + /// Configuration for scalable_matrix_with_tiered_pricing pricing + /// + public required NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig ScalableMatrixWithTieredPricingConfig { get { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_tiered_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_tiered_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_tiered_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_tiered_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_tiered_pricing_config" + ); } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_tiered_pricing_config", value); } } /// @@ -124,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -185,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -245,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -267,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -285,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -305,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -328,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -350,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -368,26 +228,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ScalableMatrixWithTieredPricingConfig.Values) - { - _ = item; - } + this.ScalableMatrixWithTieredPricingConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -399,32 +251,728 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewPlanScalableMatrixWithTieredPricingPrice() { } + + public NewPlanScalableMatrixWithTieredPricingPrice( + NewPlanScalableMatrixWithTieredPricingPrice newPlanScalableMatrixWithTieredPricingPrice + ) + : base(newPlanScalableMatrixWithTieredPricingPrice) { } + + public NewPlanScalableMatrixWithTieredPricingPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanScalableMatrixWithTieredPricingPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanScalableMatrixWithTieredPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithTieredPricingPriceFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithTieredPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanScalableMatrixWithTieredPricingPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanScalableMatrixWithTieredPricingPriceCadenceConverter))] +public enum NewPlanScalableMatrixWithTieredPricingPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanScalableMatrixWithTieredPricingPriceCadenceConverter + : JsonConverter +{ + public override NewPlanScalableMatrixWithTieredPricingPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual, + "semi_annual" => NewPlanScalableMatrixWithTieredPricingPriceCadence.SemiAnnual, + "monthly" => NewPlanScalableMatrixWithTieredPricingPriceCadence.Monthly, + "quarterly" => NewPlanScalableMatrixWithTieredPricingPriceCadence.Quarterly, + "one_time" => NewPlanScalableMatrixWithTieredPricingPriceCadence.OneTime, + "custom" => NewPlanScalableMatrixWithTieredPricingPriceCadence.Custom, + _ => (NewPlanScalableMatrixWithTieredPricingPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanScalableMatrixWithTieredPricingPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewPlanScalableMatrixWithTieredPricingPriceCadence.Annual => "annual", + NewPlanScalableMatrixWithTieredPricingPriceCadence.SemiAnnual => "semi_annual", + NewPlanScalableMatrixWithTieredPricingPriceCadence.Monthly => "monthly", + NewPlanScalableMatrixWithTieredPricingPriceCadence.Quarterly => "quarterly", + NewPlanScalableMatrixWithTieredPricingPriceCadence.OneTime => "one_time", + NewPlanScalableMatrixWithTieredPricingPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanScalableMatrixWithTieredPricingPriceModelTypeConverter))] +public enum NewPlanScalableMatrixWithTieredPricingPriceModelType +{ + ScalableMatrixWithTieredPricing, +} + +sealed class NewPlanScalableMatrixWithTieredPricingPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanScalableMatrixWithTieredPricingPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "scalable_matrix_with_tiered_pricing" => + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + _ => (NewPlanScalableMatrixWithTieredPricingPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanScalableMatrixWithTieredPricingPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing => + "scalable_matrix_with_tiered_pricing", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_tiered_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig, + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigFromRaw + >) +)] +public sealed record class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + : JsonModel +{ + /// + /// Used for the scalable matrix first dimension + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } } - public NewPlanScalableMatrixWithTieredPricingPrice() { } + /// + /// Tier pricing structure + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// Used for the scalable matrix second dimension (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.SecondDimension; + } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig() { } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig( + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig newPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig + ) + : base(newPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig) { } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanScalableMatrixWithTieredPricingPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig( + FrozenDictionary rawData ) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewPlanScalableMatrixWithTieredPricingPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor, + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactorFromRaw + >) +)] +public sealed record class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor() + { } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor newPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + ) + : base( + newPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor + ) { } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigMatrixScalingFactor.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single tier entry with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier, + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTierFromRaw + >) +)] +public sealed record class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier + : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier() + { } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier( + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier newPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier + ) + : base(newPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier) + { } + + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanScalableMatrixWithTieredPricingPriceScalableMatrixWithTieredPricingConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfigConverter))] +public record class NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanScalableMatrixWithTieredPricingPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/Cadence.cs deleted file mode 100644 index de78a36e..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 0accc1f3..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 94d7c1ee..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanScalableMatrixWithTieredPricingPriceProperties = Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ModelType.cs deleted file mode 100644 index 5d72e544..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithTieredPricingPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanScalableMatrixWithTieredPricingPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithTieredPricing = new( - "scalable_matrix_with_tiered_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithTieredPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_tiered_pricing" => Value.ScalableMatrixWithTieredPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPrice.cs b/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPrice.cs index 5b9e810e..e248da7d 100644 --- a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPrice.cs +++ b/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPrice.cs @@ -1,38 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanScalableMatrixWithUnitPricingPriceProperties = Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithUnitPricingPrice, + NewPlanScalableMatrixWithUnitPricingPriceFromRaw + >) )] -public sealed record class NewPlanScalableMatrixWithUnitPricingPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewPlanScalableMatrixWithUnitPricingPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanScalableMatrixWithUnitPricingPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -40,35 +36,22 @@ public sealed record class NewPlanScalableMatrixWithUnitPricingPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanScalableMatrixWithUnitPricingPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -76,47 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithUnitPricingConfig + /// + /// Configuration for scalable_matrix_with_unit_pricing pricing + /// + public required NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig ScalableMatrixWithUnitPricingConfig { get { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_unit_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_unit_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_unit_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_unit_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_unit_pricing_config" + ); } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_unit_pricing_config", value); } } /// @@ -124,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -185,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -245,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -267,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -285,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -305,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -328,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -350,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -368,26 +228,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ScalableMatrixWithUnitPricingConfig.Values) - { - _ = item; - } + this.ScalableMatrixWithUnitPricingConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -399,32 +251,644 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewPlanScalableMatrixWithUnitPricingPrice() { } + + public NewPlanScalableMatrixWithUnitPricingPrice( + NewPlanScalableMatrixWithUnitPricingPrice newPlanScalableMatrixWithUnitPricingPrice + ) + : base(newPlanScalableMatrixWithUnitPricingPrice) { } + + public NewPlanScalableMatrixWithUnitPricingPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanScalableMatrixWithUnitPricingPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanScalableMatrixWithUnitPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithUnitPricingPriceFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithUnitPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanScalableMatrixWithUnitPricingPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanScalableMatrixWithUnitPricingPriceCadenceConverter))] +public enum NewPlanScalableMatrixWithUnitPricingPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanScalableMatrixWithUnitPricingPriceCadenceConverter + : JsonConverter +{ + public override NewPlanScalableMatrixWithUnitPricingPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual, + "semi_annual" => NewPlanScalableMatrixWithUnitPricingPriceCadence.SemiAnnual, + "monthly" => NewPlanScalableMatrixWithUnitPricingPriceCadence.Monthly, + "quarterly" => NewPlanScalableMatrixWithUnitPricingPriceCadence.Quarterly, + "one_time" => NewPlanScalableMatrixWithUnitPricingPriceCadence.OneTime, + "custom" => NewPlanScalableMatrixWithUnitPricingPriceCadence.Custom, + _ => (NewPlanScalableMatrixWithUnitPricingPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanScalableMatrixWithUnitPricingPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewPlanScalableMatrixWithUnitPricingPriceCadence.Annual => "annual", + NewPlanScalableMatrixWithUnitPricingPriceCadence.SemiAnnual => "semi_annual", + NewPlanScalableMatrixWithUnitPricingPriceCadence.Monthly => "monthly", + NewPlanScalableMatrixWithUnitPricingPriceCadence.Quarterly => "quarterly", + NewPlanScalableMatrixWithUnitPricingPriceCadence.OneTime => "one_time", + NewPlanScalableMatrixWithUnitPricingPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanScalableMatrixWithUnitPricingPriceModelTypeConverter))] +public enum NewPlanScalableMatrixWithUnitPricingPriceModelType +{ + ScalableMatrixWithUnitPricing, +} + +sealed class NewPlanScalableMatrixWithUnitPricingPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanScalableMatrixWithUnitPricingPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "scalable_matrix_with_unit_pricing" => + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + _ => (NewPlanScalableMatrixWithUnitPricingPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanScalableMatrixWithUnitPricingPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing => + "scalable_matrix_with_unit_pricing", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_unit_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig, + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigFromRaw + >) +)] +public sealed record class NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } } - public NewPlanScalableMatrixWithUnitPricingPrice() { } + /// + /// The final unit price to rate against the output of the matrix + /// + public required string UnitPrice + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_price"); } + init { JsonModel.Set(this._rawData, "unit_price", value); } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + /// Used to determine the unit rate (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + _ = this.UnitPrice; + _ = this.Prorate; + _ = this.SecondDimension; + } + + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig() { } + + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig( + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig newPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig + ) + : base(newPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig) { } + + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanScalableMatrixWithUnitPricingPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig( + FrozenDictionary rawData ) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewPlanScalableMatrixWithUnitPricingPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor, + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + >) +)] +public sealed record class NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor() + { } + + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor newPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + ) + : base( + newPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor + ) { } + + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanScalableMatrixWithUnitPricingPriceScalableMatrixWithUnitPricingConfigMatrixScalingFactor.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfigConverter))] +public record class NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanScalableMatrixWithUnitPricingPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/Cadence.cs deleted file mode 100644 index 8f22b113..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index ba3f61b3..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8265913b..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanScalableMatrixWithUnitPricingPriceProperties = Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ModelType.cs deleted file mode 100644 index 776032b3..00000000 --- a/src/Orb/Models/NewPlanScalableMatrixWithUnitPricingPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanScalableMatrixWithUnitPricingPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithUnitPricing = new( - "scalable_matrix_with_unit_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithUnitPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_unit_pricing" => Value.ScalableMatrixWithUnitPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanThresholdTotalAmountPrice.cs b/src/Orb/Models/NewPlanThresholdTotalAmountPrice.cs index 641fd83a..de994a38 100644 --- a/src/Orb/Models/NewPlanThresholdTotalAmountPrice.cs +++ b/src/Orb/Models/NewPlanThresholdTotalAmountPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanThresholdTotalAmountPriceProperties = Orb.Models.NewPlanThresholdTotalAmountPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanThresholdTotalAmountPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanThresholdTotalAmountPrice, + NewPlanThresholdTotalAmountPriceFromRaw + >) +)] +public sealed record class NewPlanThresholdTotalAmountPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanThresholdTotalAmountPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +36,22 @@ public sealed record class NewPlanThresholdTotalAmountPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanThresholdTotalAmountPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,41 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary ThresholdTotalAmountConfig + /// + /// Configuration for threshold_total_amount pricing + /// + public required NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig ThresholdTotalAmountConfig { get { - if ( - !this.Properties.TryGetValue( - "threshold_total_amount_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "threshold_total_amount_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("threshold_total_amount_config"); - } - set - { - this.Properties["threshold_total_amount_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "threshold_total_amount_config" + ); } + init { JsonModel.Set(this._rawData, "threshold_total_amount_config", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanThresholdTotalAmountPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanThresholdTotalAmountPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,26 +228,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ThresholdTotalAmountConfig.Values) - { - _ = item; - } + this.ThresholdTotalAmountConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -391,30 +251,604 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanThresholdTotalAmountPrice() { } + public NewPlanThresholdTotalAmountPrice( + NewPlanThresholdTotalAmountPrice newPlanThresholdTotalAmountPrice + ) + : base(newPlanThresholdTotalAmountPrice) { } + + public NewPlanThresholdTotalAmountPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanThresholdTotalAmountPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanThresholdTotalAmountPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanThresholdTotalAmountPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanThresholdTotalAmountPriceFromRaw : IFromRawJson +{ + /// + public NewPlanThresholdTotalAmountPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanThresholdTotalAmountPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanThresholdTotalAmountPriceCadenceConverter))] +public enum NewPlanThresholdTotalAmountPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanThresholdTotalAmountPriceCadenceConverter + : JsonConverter +{ + public override NewPlanThresholdTotalAmountPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanThresholdTotalAmountPriceCadence.Annual, + "semi_annual" => NewPlanThresholdTotalAmountPriceCadence.SemiAnnual, + "monthly" => NewPlanThresholdTotalAmountPriceCadence.Monthly, + "quarterly" => NewPlanThresholdTotalAmountPriceCadence.Quarterly, + "one_time" => NewPlanThresholdTotalAmountPriceCadence.OneTime, + "custom" => NewPlanThresholdTotalAmountPriceCadence.Custom, + _ => (NewPlanThresholdTotalAmountPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanThresholdTotalAmountPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanThresholdTotalAmountPriceCadence.Annual => "annual", + NewPlanThresholdTotalAmountPriceCadence.SemiAnnual => "semi_annual", + NewPlanThresholdTotalAmountPriceCadence.Monthly => "monthly", + NewPlanThresholdTotalAmountPriceCadence.Quarterly => "quarterly", + NewPlanThresholdTotalAmountPriceCadence.OneTime => "one_time", + NewPlanThresholdTotalAmountPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanThresholdTotalAmountPriceModelTypeConverter))] +public enum NewPlanThresholdTotalAmountPriceModelType +{ + ThresholdTotalAmount, +} + +sealed class NewPlanThresholdTotalAmountPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanThresholdTotalAmountPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "threshold_total_amount" => + NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + _ => (NewPlanThresholdTotalAmountPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanThresholdTotalAmountPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanThresholdTotalAmountPriceModelType.ThresholdTotalAmount => + "threshold_total_amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for threshold_total_amount pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig, + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigFromRaw + >) +)] +public sealed record class NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig : JsonModel +{ + /// + /// When the quantity consumed passes a provided threshold, the configured total + /// will be charged + /// + public required IReadOnlyList ConsumptionTable + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "consumption_table"); + } + init { JsonModel.Set(this._rawData, "consumption_table", value); } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.ConsumptionTable) + { + item.Validate(); + } + _ = this.Prorate; + } + + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig() { } + + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig( + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig newPlanThresholdTotalAmountPriceThresholdTotalAmountConfig + ) + : base(newPlanThresholdTotalAmountPriceThresholdTotalAmountConfig) { } + + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig( + List consumptionTable + ) + : this() + { + this.ConsumptionTable = consumptionTable; + } +} + +class NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single threshold +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable, + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTableFromRaw + >) +)] +public sealed record class NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable + : JsonModel +{ + /// + /// Quantity threshold + /// + public required string Threshold + { + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } + } + + /// + /// Total amount for this threshold + /// + public required string TotalAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "total_amount"); } + init { JsonModel.Set(this._rawData, "total_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Threshold; + _ = this.TotalAmount; + } + + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable() { } + + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable( + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable newPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable + ) + : base(newPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable) { } + + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTableFromRaw + : IFromRawJson +{ + /// + public NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanThresholdTotalAmountPriceThresholdTotalAmountConfigConsumptionTable.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(NewPlanThresholdTotalAmountPriceConversionRateConfigConverter))] +public record class NewPlanThresholdTotalAmountPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanThresholdTotalAmountPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanThresholdTotalAmountPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanThresholdTotalAmountPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanThresholdTotalAmountPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanThresholdTotalAmountPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanThresholdTotalAmountPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanThresholdTotalAmountPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanThresholdTotalAmountPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanThresholdTotalAmountPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanThresholdTotalAmountPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanThresholdTotalAmountPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanThresholdTotalAmountPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanThresholdTotalAmountPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/Cadence.cs deleted file mode 100644 index 71f695bf..00000000 --- a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanThresholdTotalAmountPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 0cbd035e..00000000 --- a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanThresholdTotalAmountPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanThresholdTotalAmountPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index fcb2044b..00000000 --- a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanThresholdTotalAmountPriceProperties = Orb.Models.NewPlanThresholdTotalAmountPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanThresholdTotalAmountPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanThresholdTotalAmountPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanThresholdTotalAmountPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ModelType.cs deleted file mode 100644 index 9e24c317..00000000 --- a/src/Orb/Models/NewPlanThresholdTotalAmountPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanThresholdTotalAmountPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ThresholdTotalAmount = new("threshold_total_amount"); - - readonly string _value = value; - - public enum Value - { - ThresholdTotalAmount, - } - - public Value Known() => - _value switch - { - "threshold_total_amount" => Value.ThresholdTotalAmount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTierWithProrationPrice.cs b/src/Orb/Models/NewPlanTierWithProrationPrice.cs deleted file mode 100644 index 3d3f69a0..00000000 --- a/src/Orb/Models/NewPlanTierWithProrationPrice.cs +++ /dev/null @@ -1,420 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanTierWithProrationPriceProperties = Orb.Models.NewPlanTierWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanTierWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The cadence to bill for this price on. - /// - public required NewPlanTierWithProrationPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewPlanTierWithProrationPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::Dictionary TieredWithProrationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "tiered_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_proration_config"); - } - set - { - this.Properties["tiered_with_proration_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewPlanTierWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - foreach (var item in this.TieredWithProrationConfig.Values) - { - _ = item; - } - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewPlanTierWithProrationPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanTierWithProrationPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewPlanTierWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanTierWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index c017a093..00000000 --- a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTierWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index d81309f3..00000000 --- a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanTierWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTierWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index a7c3f85f..00000000 --- a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanTierWithProrationPriceProperties = Orb.Models.NewPlanTierWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTierWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanTierWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanTierWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index b0dfb815..00000000 --- a/src/Orb/Models/NewPlanTierWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTierWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithProration = new("tiered_with_proration"); - - readonly string _value = value; - - public enum Value - { - TieredWithProration, - } - - public Value Known() => - _value switch - { - "tiered_with_proration" => Value.TieredWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredBPSPrice.cs b/src/Orb/Models/NewPlanTieredBPSPrice.cs deleted file mode 100644 index 6fb37135..00000000 --- a/src/Orb/Models/NewPlanTieredBPSPrice.cs +++ /dev/null @@ -1,410 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanTieredBPSPriceProperties = Orb.Models.NewPlanTieredBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanTieredBPSPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The cadence to bill for this price on. - /// - public required NewPlanTieredBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewPlanTieredBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredBPSConfig TieredBPSConfig - { - get - { - if (!this.Properties.TryGetValue("tiered_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_bps_config"); - } - set - { - this.Properties["tiered_bps_config"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewPlanTieredBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - this.TieredBPSConfig.Validate(); - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewPlanTieredBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanTieredBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewPlanTieredBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/NewPlanTieredBPSPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanTieredBPSPriceProperties/Cadence.cs deleted file mode 100644 index ad1a9b34..00000000 --- a/src/Orb/Models/NewPlanTieredBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanTieredBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index d4f35159..00000000 --- a/src/Orb/Models/NewPlanTieredBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanTieredBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 846930df..00000000 --- a/src/Orb/Models/NewPlanTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanTieredBPSPriceProperties = Orb.Models.NewPlanTieredBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanTieredBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanTieredBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanTieredBPSPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanTieredBPSPriceProperties/ModelType.cs deleted file mode 100644 index 8ffc8d46..00000000 --- a/src/Orb/Models/NewPlanTieredBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredBPS = new("tiered_bps"); - - readonly string _value = value; - - public enum Value - { - TieredBPS, - } - - public Value Known() => - _value switch - { - "tiered_bps" => Value.TieredBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredPackagePrice.cs b/src/Orb/Models/NewPlanTieredPackagePrice.cs index 80ce026f..8faceaff 100644 --- a/src/Orb/Models/NewPlanTieredPackagePrice.cs +++ b/src/Orb/Models/NewPlanTieredPackagePrice.cs @@ -1,36 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanTieredPackagePriceProperties = Orb.Models.NewPlanTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +34,23 @@ public sealed record class NewPlanTieredPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,39 +58,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredPackageConfig + /// + /// Configuration for tiered_package pricing + /// + public required NewPlanTieredPackagePriceTieredPackageConfig TieredPackageConfig { get { - if ( - !this.Properties.TryGetValue("tiered_package_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_config"); - } - set - { - this.Properties["tiered_package_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_config" ); } + init { JsonModel.Set(this._rawData, "tiered_package_config", value); } } /// @@ -114,60 +82,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -175,57 +117,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -235,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -257,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -275,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -295,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -318,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -340,16 +209,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -358,26 +227,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredPackageConfig.Values) - { - _ = item; - } + this.TieredPackageConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -389,30 +250,585 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanTieredPackagePrice() { } + public NewPlanTieredPackagePrice(NewPlanTieredPackagePrice newPlanTieredPackagePrice) + : base(newPlanTieredPackagePrice) { } + + public NewPlanTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanTieredPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPackagePriceFromRaw : IFromRawJson +{ + /// + public NewPlanTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanTieredPackagePriceCadenceConverter))] +public enum NewPlanTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewPlanTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanTieredPackagePriceCadence.Annual, + "semi_annual" => NewPlanTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewPlanTieredPackagePriceCadence.Monthly, + "quarterly" => NewPlanTieredPackagePriceCadence.Quarterly, + "one_time" => NewPlanTieredPackagePriceCadence.OneTime, + "custom" => NewPlanTieredPackagePriceCadence.Custom, + _ => (NewPlanTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredPackagePriceCadence.Annual => "annual", + NewPlanTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewPlanTieredPackagePriceCadence.Monthly => "monthly", + NewPlanTieredPackagePriceCadence.Quarterly => "quarterly", + NewPlanTieredPackagePriceCadence.OneTime => "one_time", + NewPlanTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanTieredPackagePriceModelTypeConverter))] +public enum NewPlanTieredPackagePriceModelType +{ + TieredPackage, +} + +sealed class NewPlanTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewPlanTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_package" => NewPlanTieredPackagePriceModelType.TieredPackage, + _ => (NewPlanTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredPackagePriceModelType.TieredPackage => "tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredPackagePriceTieredPackageConfig, + NewPlanTieredPackagePriceTieredPackageConfigFromRaw + >) +)] +public sealed record class NewPlanTieredPackagePriceTieredPackageConfig : JsonModel +{ + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. The tier bounds are defined + /// based on the total quantity rather than the number of packages, so they must + /// be multiples of the package size. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public NewPlanTieredPackagePriceTieredPackageConfig() { } + + public NewPlanTieredPackagePriceTieredPackageConfig( + NewPlanTieredPackagePriceTieredPackageConfig newPlanTieredPackagePriceTieredPackageConfig + ) + : base(newPlanTieredPackagePriceTieredPackageConfig) { } + + public NewPlanTieredPackagePriceTieredPackageConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanTieredPackagePriceTieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanTieredPackagePriceTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPackagePriceTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredPackagePriceTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredPackagePriceTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredPackagePriceTieredPackageConfigTier, + NewPlanTieredPackagePriceTieredPackageConfigTierFromRaw + >) +)] +public sealed record class NewPlanTieredPackagePriceTieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public NewPlanTieredPackagePriceTieredPackageConfigTier() { } + + public NewPlanTieredPackagePriceTieredPackageConfigTier( + NewPlanTieredPackagePriceTieredPackageConfigTier newPlanTieredPackagePriceTieredPackageConfigTier + ) + : base(newPlanTieredPackagePriceTieredPackageConfigTier) { } + + public NewPlanTieredPackagePriceTieredPackageConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanTieredPackagePriceTieredPackageConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanTieredPackagePriceTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPackagePriceTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredPackagePriceTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredPackagePriceTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewPlanTieredPackagePriceConversionRateConfigConverter))] +public record class NewPlanTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/NewPlanTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index 0e5ed8cc..00000000 --- a/src/Orb/Models/NewPlanTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index f60a21bf..00000000 --- a/src/Orb/Models/NewPlanTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index c6dad186..00000000 --- a/src/Orb/Models/NewPlanTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanTieredPackagePriceProperties = Orb.Models.NewPlanTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/NewPlanTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index dfde746d..00000000 --- a/src/Orb/Models/NewPlanTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackage = new("tiered_package"); - - readonly string _value = value; - - public enum Value - { - TieredPackage, - } - - public Value Known() => - _value switch - { - "tiered_package" => Value.TieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredPackageWithMinimumPrice.cs b/src/Orb/Models/NewPlanTieredPackageWithMinimumPrice.cs index 2a107d58..b3872db7 100644 --- a/src/Orb/Models/NewPlanTieredPackageWithMinimumPrice.cs +++ b/src/Orb/Models/NewPlanTieredPackageWithMinimumPrice.cs @@ -1,36 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanTieredPackageWithMinimumPriceProperties = Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanTieredPackageWithMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredPackageWithMinimumPrice, + NewPlanTieredPackageWithMinimumPriceFromRaw + >) +)] +public sealed record class NewPlanTieredPackageWithMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanTieredPackageWithMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +36,22 @@ public sealed record class NewPlanTieredPackageWithMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanTieredPackageWithMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,41 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredPackageWithMinimumConfig + /// + /// Configuration for tiered_package_with_minimum pricing + /// + public required NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig TieredPackageWithMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_package_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_with_minimum_config"); - } - set - { - this.Properties["tiered_package_with_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_with_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "tiered_package_with_minimum_config", value); } } /// @@ -116,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -177,57 +118,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanTieredPackageWithMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanTieredPackageWithMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -237,21 +154,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -259,17 +167,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -277,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -297,19 +185,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -320,21 +197,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -342,16 +210,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -360,26 +228,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredPackageWithMinimumConfig.Values) - { - _ = item; - } + this.TieredPackageWithMinimumConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -391,30 +251,610 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanTieredPackageWithMinimumPrice() { } + public NewPlanTieredPackageWithMinimumPrice( + NewPlanTieredPackageWithMinimumPrice newPlanTieredPackageWithMinimumPrice + ) + : base(newPlanTieredPackageWithMinimumPrice) { } + + public NewPlanTieredPackageWithMinimumPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanTieredPackageWithMinimumPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanTieredPackageWithMinimumPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanTieredPackageWithMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPackageWithMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredPackageWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredPackageWithMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanTieredPackageWithMinimumPriceCadenceConverter))] +public enum NewPlanTieredPackageWithMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanTieredPackageWithMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewPlanTieredPackageWithMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanTieredPackageWithMinimumPriceCadence.Annual, + "semi_annual" => NewPlanTieredPackageWithMinimumPriceCadence.SemiAnnual, + "monthly" => NewPlanTieredPackageWithMinimumPriceCadence.Monthly, + "quarterly" => NewPlanTieredPackageWithMinimumPriceCadence.Quarterly, + "one_time" => NewPlanTieredPackageWithMinimumPriceCadence.OneTime, + "custom" => NewPlanTieredPackageWithMinimumPriceCadence.Custom, + _ => (NewPlanTieredPackageWithMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPackageWithMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredPackageWithMinimumPriceCadence.Annual => "annual", + NewPlanTieredPackageWithMinimumPriceCadence.SemiAnnual => "semi_annual", + NewPlanTieredPackageWithMinimumPriceCadence.Monthly => "monthly", + NewPlanTieredPackageWithMinimumPriceCadence.Quarterly => "quarterly", + NewPlanTieredPackageWithMinimumPriceCadence.OneTime => "one_time", + NewPlanTieredPackageWithMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanTieredPackageWithMinimumPriceModelTypeConverter))] +public enum NewPlanTieredPackageWithMinimumPriceModelType +{ + TieredPackageWithMinimum, +} + +sealed class NewPlanTieredPackageWithMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanTieredPackageWithMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_package_with_minimum" => + NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + _ => (NewPlanTieredPackageWithMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPackageWithMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum => + "tiered_package_with_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig, + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigFromRaw + >) +)] +public sealed record class NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + : JsonModel +{ + /// + /// Package size + /// + public required double PackageSize + { + get { return JsonModel.GetNotNullStruct(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig() { } + + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig( + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig newPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig + ) + : base(newPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig) { } + + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier, + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTierFromRaw + >) +)] +public sealed record class NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier + : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier() { } + + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier( + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier newPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier + ) + : base(newPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier) { } + + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + NewPlanTieredPackageWithMinimumPriceTieredPackageWithMinimumConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(NewPlanTieredPackageWithMinimumPriceConversionRateConfigConverter))] +public record class NewPlanTieredPackageWithMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanTieredPackageWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredPackageWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredPackageWithMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPackageWithMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPackageWithMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanTieredPackageWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanTieredPackageWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPackageWithMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanTieredPackageWithMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanTieredPackageWithMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanTieredPackageWithMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanTieredPackageWithMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPackageWithMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 8c5bc461..00000000 --- a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index b6423460..00000000 --- a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 50f8b2b2..00000000 --- a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanTieredPackageWithMinimumPriceProperties = Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanTieredPackageWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanTieredPackageWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ModelType.cs deleted file mode 100644 index f374c84d..00000000 --- a/src/Orb/Models/NewPlanTieredPackageWithMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredPackageWithMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackageWithMinimum = new("tiered_package_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredPackageWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_package_with_minimum" => Value.TieredPackageWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredPrice.cs b/src/Orb/Models/NewPlanTieredPrice.cs index 9c19aa21..67b6becc 100644 --- a/src/Orb/Models/NewPlanTieredPrice.cs +++ b/src/Orb/Models/NewPlanTieredPrice.cs @@ -1,33 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanTieredPriceProperties = Orb.Models.NewPlanTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanTieredPrice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewPlanTieredPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanTieredPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -35,35 +32,23 @@ public sealed record class NewPlanTieredPrice : Orb::ModelBase, Orb::IFromRaw public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanTieredPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -71,31 +56,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// + /// Configuration for tiered pricing + /// public required TieredConfig TieredConfig { - get - { - if (!this.Properties.TryGetValue("tiered_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_config"); - } - set { this.Properties["tiered_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "tiered_config"); } + init { JsonModel.Set(this._rawData, "tiered_config", value); } } /// @@ -103,60 +74,34 @@ public required TieredConfig TieredConfig /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -164,57 +109,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanTieredPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanTieredPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -224,21 +145,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -246,17 +158,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -264,19 +167,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -284,19 +176,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -307,21 +188,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -329,16 +201,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -347,16 +219,11 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -375,30 +242,419 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanTieredPrice() { } + public NewPlanTieredPrice(NewPlanTieredPrice newPlanTieredPrice) + : base(newPlanTieredPrice) { } + + public NewPlanTieredPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanTieredPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanTieredPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanTieredPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredPriceFromRaw : IFromRawJson +{ + /// + public NewPlanTieredPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + NewPlanTieredPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanTieredPriceCadenceConverter))] +public enum NewPlanTieredPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanTieredPriceCadenceConverter : JsonConverter +{ + public override NewPlanTieredPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanTieredPriceCadence.Annual, + "semi_annual" => NewPlanTieredPriceCadence.SemiAnnual, + "monthly" => NewPlanTieredPriceCadence.Monthly, + "quarterly" => NewPlanTieredPriceCadence.Quarterly, + "one_time" => NewPlanTieredPriceCadence.OneTime, + "custom" => NewPlanTieredPriceCadence.Custom, + _ => (NewPlanTieredPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredPriceCadence.Annual => "annual", + NewPlanTieredPriceCadence.SemiAnnual => "semi_annual", + NewPlanTieredPriceCadence.Monthly => "monthly", + NewPlanTieredPriceCadence.Quarterly => "quarterly", + NewPlanTieredPriceCadence.OneTime => "one_time", + NewPlanTieredPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanTieredPriceModelTypeConverter))] +public enum NewPlanTieredPriceModelType +{ + Tiered, +} + +sealed class NewPlanTieredPriceModelTypeConverter : JsonConverter +{ + public override NewPlanTieredPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered" => NewPlanTieredPriceModelType.Tiered, + _ => (NewPlanTieredPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredPriceModelType.Tiered => "tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanTieredPriceConversionRateConfigConverter))] +public record class NewPlanTieredPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanTieredPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanTieredPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanTieredPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanTieredPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanTieredPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanTieredPriceProperties/Cadence.cs deleted file mode 100644 index 31aa3b7f..00000000 --- a/src/Orb/Models/NewPlanTieredPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanTieredPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 1ca013e2..00000000 --- a/src/Orb/Models/NewPlanTieredPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanTieredPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanTieredPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanTieredPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 838b1c41..00000000 --- a/src/Orb/Models/NewPlanTieredPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanTieredPriceProperties = Orb.Models.NewPlanTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanTieredPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanTieredPriceProperties/ModelType.cs deleted file mode 100644 index 9571bf49..00000000 --- a/src/Orb/Models/NewPlanTieredPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Tiered = new("tiered"); - - readonly string _value = value; - - public enum Value - { - Tiered, - } - - public Value Known() => - _value switch - { - "tiered" => Value.Tiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredWithMinimumPrice.cs b/src/Orb/Models/NewPlanTieredWithMinimumPrice.cs index 6d3dce7f..db93d652 100644 --- a/src/Orb/Models/NewPlanTieredWithMinimumPrice.cs +++ b/src/Orb/Models/NewPlanTieredWithMinimumPrice.cs @@ -1,36 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanTieredWithMinimumPriceProperties = Orb.Models.NewPlanTieredWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanTieredWithMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanTieredWithMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanTieredWithMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +34,22 @@ public sealed record class NewPlanTieredWithMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanTieredWithMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,42 +57,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredWithMinimumConfig + /// + /// Configuration for tiered_with_minimum pricing + /// + public required NewPlanTieredWithMinimumPriceTieredWithMinimumConfig TieredWithMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_minimum_config"); - } - set - { - this.Properties["tiered_with_minimum_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_minimum_config" ); } + init { JsonModel.Set(this._rawData, "tiered_with_minimum_config", value); } } /// @@ -117,60 +81,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -178,57 +116,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanTieredWithMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanTieredWithMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -238,21 +152,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +165,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +174,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +183,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +195,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +208,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,26 +226,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredWithMinimumConfig.Values) - { - _ = item; - } + this.TieredWithMinimumConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -392,30 +249,634 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewPlanTieredWithMinimumPrice() { } + + public NewPlanTieredWithMinimumPrice( + NewPlanTieredWithMinimumPrice newPlanTieredWithMinimumPrice + ) + : base(newPlanTieredWithMinimumPrice) { } + + public NewPlanTieredWithMinimumPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanTieredWithMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanTieredWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredWithMinimumPriceFromRaw : IFromRawJson +{ + /// + public NewPlanTieredWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredWithMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanTieredWithMinimumPriceCadenceConverter))] +public enum NewPlanTieredWithMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanTieredWithMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewPlanTieredWithMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanTieredWithMinimumPriceCadence.Annual, + "semi_annual" => NewPlanTieredWithMinimumPriceCadence.SemiAnnual, + "monthly" => NewPlanTieredWithMinimumPriceCadence.Monthly, + "quarterly" => NewPlanTieredWithMinimumPriceCadence.Quarterly, + "one_time" => NewPlanTieredWithMinimumPriceCadence.OneTime, + "custom" => NewPlanTieredWithMinimumPriceCadence.Custom, + _ => (NewPlanTieredWithMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredWithMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredWithMinimumPriceCadence.Annual => "annual", + NewPlanTieredWithMinimumPriceCadence.SemiAnnual => "semi_annual", + NewPlanTieredWithMinimumPriceCadence.Monthly => "monthly", + NewPlanTieredWithMinimumPriceCadence.Quarterly => "quarterly", + NewPlanTieredWithMinimumPriceCadence.OneTime => "one_time", + NewPlanTieredWithMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanTieredWithMinimumPriceModelTypeConverter))] +public enum NewPlanTieredWithMinimumPriceModelType +{ + TieredWithMinimum, +} + +sealed class NewPlanTieredWithMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanTieredWithMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_with_minimum" => NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum, + _ => (NewPlanTieredWithMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredWithMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanTieredWithMinimumPriceModelType.TieredWithMinimum => "tiered_with_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredWithMinimumPriceTieredWithMinimumConfig, + NewPlanTieredWithMinimumPriceTieredWithMinimumConfigFromRaw + >) +)] +public sealed record class NewPlanTieredWithMinimumPriceTieredWithMinimumConfig : JsonModel +{ + /// + /// Tiered pricing with a minimum amount dependent on the volume tier. Tiers + /// are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get { - foreach (var item in this.Metadata.Values) + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// If true, tiers with an accrued amount of 0 will not be included in the rating. + /// + public bool? HideZeroAmountTiers + { + get { return JsonModel.GetNullableStruct(this.RawData, "hide_zero_amount_tiers"); } + init + { + if (value == null) { - _ = item; + return; } + + JsonModel.Set(this._rawData, "hide_zero_amount_tiers", value); } - _ = this.ReferenceID; } - public NewPlanTieredWithMinimumPrice() { } + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorate", value); + } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.HideZeroAmountTiers; + _ = this.Prorate; + } + + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfig() { } + + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfig( + NewPlanTieredWithMinimumPriceTieredWithMinimumConfig newPlanTieredWithMinimumPriceTieredWithMinimumConfig + ) + : base(newPlanTieredWithMinimumPriceTieredWithMinimumConfig) { } + + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanTieredWithMinimumPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanTieredWithMinimumPriceTieredWithMinimumConfig( + FrozenDictionary rawData + ) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewPlanTieredWithMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static NewPlanTieredWithMinimumPriceTieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class NewPlanTieredWithMinimumPriceTieredWithMinimumConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredWithMinimumPriceTieredWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier, + NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTierFromRaw + >) +)] +public sealed record class NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier() { } + + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier( + NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier newPlanTieredWithMinimumPriceTieredWithMinimumConfigTier + ) + : base(newPlanTieredWithMinimumPriceTieredWithMinimumConfigTier) { } + + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTierFromRaw + : IFromRawJson +{ + /// + public NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanTieredWithMinimumPriceTieredWithMinimumConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewPlanTieredWithMinimumPriceConversionRateConfigConverter))] +public record class NewPlanTieredWithMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanTieredWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanTieredWithMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredWithMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredWithMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanTieredWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanTieredWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanTieredWithMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanTieredWithMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanTieredWithMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanTieredWithMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanTieredWithMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanTieredWithMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 4f4fc11b..00000000 --- a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredWithMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 340fd99a..00000000 --- a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanTieredWithMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredWithMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 27ae9976..00000000 --- a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanTieredWithMinimumPriceProperties = Orb.Models.NewPlanTieredWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanTieredWithMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanTieredWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanTieredWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ModelType.cs deleted file mode 100644 index eb6b359f..00000000 --- a/src/Orb/Models/NewPlanTieredWithMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanTieredWithMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithMinimum = new("tiered_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_with_minimum" => Value.TieredWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanUnitPrice.cs b/src/Orb/Models/NewPlanUnitPrice.cs index 613f29d5..117b84f1 100644 --- a/src/Orb/Models/NewPlanUnitPrice.cs +++ b/src/Orb/Models/NewPlanUnitPrice.cs @@ -1,33 +1,30 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanUnitPriceProperties = Orb.Models.NewPlanUnitPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanUnitPrice : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewPlanUnitPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanUnitPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -35,34 +32,23 @@ public sealed record class NewPlanUnitPrice : Orb::ModelBase, Orb::IFromRaw public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanUnitPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -70,31 +56,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } + /// + /// Configuration for unit pricing + /// public required UnitConfig UnitConfig { - get - { - if (!this.Properties.TryGetValue("unit_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_config"); - } - set { this.Properties["unit_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_config"); } + init { JsonModel.Set(this._rawData, "unit_config", value); } } /// @@ -102,60 +74,34 @@ public required UnitConfig UnitConfig /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -163,57 +109,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanUnitPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanUnitPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -223,21 +145,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -245,17 +158,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -263,19 +167,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -283,19 +176,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -306,21 +188,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -328,16 +201,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -346,16 +219,11 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -374,30 +242,419 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanUnitPrice() { } + public NewPlanUnitPrice(NewPlanUnitPrice newPlanUnitPrice) + : base(newPlanUnitPrice) { } + + public NewPlanUnitPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanUnitPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanUnitPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanUnitPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanUnitPriceFromRaw : IFromRawJson +{ + /// + public NewPlanUnitPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + NewPlanUnitPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanUnitPriceCadenceConverter))] +public enum NewPlanUnitPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanUnitPriceCadenceConverter : JsonConverter +{ + public override NewPlanUnitPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanUnitPriceCadence.Annual, + "semi_annual" => NewPlanUnitPriceCadence.SemiAnnual, + "monthly" => NewPlanUnitPriceCadence.Monthly, + "quarterly" => NewPlanUnitPriceCadence.Quarterly, + "one_time" => NewPlanUnitPriceCadence.OneTime, + "custom" => NewPlanUnitPriceCadence.Custom, + _ => (NewPlanUnitPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanUnitPriceCadence.Annual => "annual", + NewPlanUnitPriceCadence.SemiAnnual => "semi_annual", + NewPlanUnitPriceCadence.Monthly => "monthly", + NewPlanUnitPriceCadence.Quarterly => "quarterly", + NewPlanUnitPriceCadence.OneTime => "one_time", + NewPlanUnitPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanUnitPriceModelTypeConverter))] +public enum NewPlanUnitPriceModelType +{ + Unit, +} + +sealed class NewPlanUnitPriceModelTypeConverter : JsonConverter +{ + public override NewPlanUnitPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit" => NewPlanUnitPriceModelType.Unit, + _ => (NewPlanUnitPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanUnitPriceModelType.Unit => "unit", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewPlanUnitPriceConversionRateConfigConverter))] +public record class NewPlanUnitPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanUnitPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanUnitPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanUnitPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanUnitPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanUnitPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanUnitPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanUnitPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanUnitPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanUnitPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanUnitPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanUnitPriceProperties/Cadence.cs deleted file mode 100644 index ef417ab8..00000000 --- a/src/Orb/Models/NewPlanUnitPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanUnitPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanUnitPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanUnitPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 06aafcd5..00000000 --- a/src/Orb/Models/NewPlanUnitPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanUnitPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanUnitPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanUnitPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanUnitPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index acf78ef6..00000000 --- a/src/Orb/Models/NewPlanUnitPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanUnitPriceProperties = Orb.Models.NewPlanUnitPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanUnitPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanUnitPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanUnitPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanUnitPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanUnitPriceProperties/ModelType.cs deleted file mode 100644 index 1a1d0727..00000000 --- a/src/Orb/Models/NewPlanUnitPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanUnitPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Unit = new("unit"); - - readonly string _value = value; - - public enum Value - { - Unit, - } - - public Value Known() => - _value switch - { - "unit" => Value.Unit, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanUnitWithPercentPrice.cs b/src/Orb/Models/NewPlanUnitWithPercentPrice.cs index 60a55dac..992d44ce 100644 --- a/src/Orb/Models/NewPlanUnitWithPercentPrice.cs +++ b/src/Orb/Models/NewPlanUnitWithPercentPrice.cs @@ -1,36 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanUnitWithPercentPriceProperties = Orb.Models.NewPlanUnitWithPercentPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanUnitWithPercentPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanUnitWithPercentPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanUnitWithPercentPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +34,23 @@ public sealed record class NewPlanUnitWithPercentPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanUnitWithPercentPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,42 +58,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary UnitWithPercentConfig + /// + /// Configuration for unit_with_percent pricing + /// + public required NewPlanUnitWithPercentPriceUnitWithPercentConfig UnitWithPercentConfig { get { - if ( - !this.Properties.TryGetValue( - "unit_with_percent_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_percent_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_percent_config"); - } - set - { - this.Properties["unit_with_percent_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_percent_config" ); } + init { JsonModel.Set(this._rawData, "unit_with_percent_config", value); } } /// @@ -117,60 +82,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -178,57 +117,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanUnitWithPercentPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanUnitWithPercentPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -238,21 +153,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +166,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +175,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +184,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +196,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +209,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,26 +227,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.UnitWithPercentConfig.Values) - { - _ = item; - } + this.UnitWithPercentConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -392,30 +250,498 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanUnitWithPercentPrice() { } + public NewPlanUnitWithPercentPrice(NewPlanUnitWithPercentPrice newPlanUnitWithPercentPrice) + : base(newPlanUnitWithPercentPrice) { } + + public NewPlanUnitWithPercentPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanUnitWithPercentPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanUnitWithPercentPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanUnitWithPercentPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanUnitWithPercentPriceFromRaw : IFromRawJson +{ + /// + public NewPlanUnitWithPercentPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanUnitWithPercentPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanUnitWithPercentPriceCadenceConverter))] +public enum NewPlanUnitWithPercentPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanUnitWithPercentPriceCadenceConverter + : JsonConverter +{ + public override NewPlanUnitWithPercentPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanUnitWithPercentPriceCadence.Annual, + "semi_annual" => NewPlanUnitWithPercentPriceCadence.SemiAnnual, + "monthly" => NewPlanUnitWithPercentPriceCadence.Monthly, + "quarterly" => NewPlanUnitWithPercentPriceCadence.Quarterly, + "one_time" => NewPlanUnitWithPercentPriceCadence.OneTime, + "custom" => NewPlanUnitWithPercentPriceCadence.Custom, + _ => (NewPlanUnitWithPercentPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitWithPercentPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanUnitWithPercentPriceCadence.Annual => "annual", + NewPlanUnitWithPercentPriceCadence.SemiAnnual => "semi_annual", + NewPlanUnitWithPercentPriceCadence.Monthly => "monthly", + NewPlanUnitWithPercentPriceCadence.Quarterly => "quarterly", + NewPlanUnitWithPercentPriceCadence.OneTime => "one_time", + NewPlanUnitWithPercentPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanUnitWithPercentPriceModelTypeConverter))] +public enum NewPlanUnitWithPercentPriceModelType +{ + UnitWithPercent, +} + +sealed class NewPlanUnitWithPercentPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanUnitWithPercentPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit_with_percent" => NewPlanUnitWithPercentPriceModelType.UnitWithPercent, + _ => (NewPlanUnitWithPercentPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitWithPercentPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanUnitWithPercentPriceModelType.UnitWithPercent => "unit_with_percent", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanUnitWithPercentPriceUnitWithPercentConfig, + NewPlanUnitWithPercentPriceUnitWithPercentConfigFromRaw + >) +)] +public sealed record class NewPlanUnitWithPercentPriceUnitWithPercentConfig : JsonModel +{ + /// + /// What percent, out of 100, of the calculated total to charge + /// + public required string Percent + { + get { return JsonModel.GetNotNullClass(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + _ = this.UnitAmount; + } + + public NewPlanUnitWithPercentPriceUnitWithPercentConfig() { } + + public NewPlanUnitWithPercentPriceUnitWithPercentConfig( + NewPlanUnitWithPercentPriceUnitWithPercentConfig newPlanUnitWithPercentPriceUnitWithPercentConfig + ) + : base(newPlanUnitWithPercentPriceUnitWithPercentConfig) { } + + public NewPlanUnitWithPercentPriceUnitWithPercentConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanUnitWithPercentPriceUnitWithPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanUnitWithPercentPriceUnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanUnitWithPercentPriceUnitWithPercentConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanUnitWithPercentPriceUnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanUnitWithPercentPriceUnitWithPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewPlanUnitWithPercentPriceConversionRateConfigConverter))] +public record class NewPlanUnitWithPercentPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanUnitWithPercentPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanUnitWithPercentPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanUnitWithPercentPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitWithPercentPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitWithPercentPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanUnitWithPercentPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanUnitWithPercentPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitWithPercentPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanUnitWithPercentPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanUnitWithPercentPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanUnitWithPercentPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanUnitWithPercentPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitWithPercentPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/Cadence.cs deleted file mode 100644 index 3843d43b..00000000 --- a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanUnitWithPercentPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 6f493364..00000000 --- a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanUnitWithPercentPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanUnitWithPercentPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 4acfedca..00000000 --- a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanUnitWithPercentPriceProperties = Orb.Models.NewPlanUnitWithPercentPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanUnitWithPercentPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanUnitWithPercentPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanUnitWithPercentPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ModelType.cs deleted file mode 100644 index d21466f2..00000000 --- a/src/Orb/Models/NewPlanUnitWithPercentPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanUnitWithPercentPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithPercent = new("unit_with_percent"); - - readonly string _value = value; - - public enum Value - { - UnitWithPercent, - } - - public Value Known() => - _value switch - { - "unit_with_percent" => Value.UnitWithPercent, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanUnitWithProrationPrice.cs b/src/Orb/Models/NewPlanUnitWithProrationPrice.cs index c22f8729..b122e496 100644 --- a/src/Orb/Models/NewPlanUnitWithProrationPrice.cs +++ b/src/Orb/Models/NewPlanUnitWithProrationPrice.cs @@ -1,36 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewPlanUnitWithProrationPriceProperties = Orb.Models.NewPlanUnitWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewPlanUnitWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewPlanUnitWithProrationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewPlanUnitWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -38,35 +34,22 @@ public sealed record class NewPlanUnitWithProrationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewPlanUnitWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -74,42 +57,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary UnitWithProrationConfig + /// + /// Configuration for unit_with_proration pricing + /// + public required NewPlanUnitWithProrationPriceUnitWithProrationConfig UnitWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "unit_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_proration_config"); - } - set - { - this.Properties["unit_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_proration_config" ); } + init { JsonModel.Set(this._rawData, "unit_with_proration_config", value); } } /// @@ -117,60 +81,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -178,57 +116,33 @@ public NewBillingCycleConfiguration? BillingCycleConfiguration /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewPlanUnitWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewPlanUnitWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -238,21 +152,12 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +165,8 @@ public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +174,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,19 +183,8 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// @@ -321,21 +195,12 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +208,16 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,26 +226,18 @@ public NewBillingCycleConfiguration? InvoicingCycleConfiguration /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.UnitWithProrationConfig.Values) - { - _ = item; - } + this.UnitWithProrationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -392,30 +249,499 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewPlanUnitWithProrationPrice() { } + public NewPlanUnitWithProrationPrice( + NewPlanUnitWithProrationPrice newPlanUnitWithProrationPrice + ) + : base(newPlanUnitWithProrationPrice) { } + + public NewPlanUnitWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewPlanUnitWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewPlanUnitWithProrationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewPlanUnitWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewPlanUnitWithProrationPriceFromRaw : IFromRawJson +{ + /// + public NewPlanUnitWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanUnitWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewPlanUnitWithProrationPriceCadenceConverter))] +public enum NewPlanUnitWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewPlanUnitWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewPlanUnitWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewPlanUnitWithProrationPriceCadence.Annual, + "semi_annual" => NewPlanUnitWithProrationPriceCadence.SemiAnnual, + "monthly" => NewPlanUnitWithProrationPriceCadence.Monthly, + "quarterly" => NewPlanUnitWithProrationPriceCadence.Quarterly, + "one_time" => NewPlanUnitWithProrationPriceCadence.OneTime, + "custom" => NewPlanUnitWithProrationPriceCadence.Custom, + _ => (NewPlanUnitWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanUnitWithProrationPriceCadence.Annual => "annual", + NewPlanUnitWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewPlanUnitWithProrationPriceCadence.Monthly => "monthly", + NewPlanUnitWithProrationPriceCadence.Quarterly => "quarterly", + NewPlanUnitWithProrationPriceCadence.OneTime => "one_time", + NewPlanUnitWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewPlanUnitWithProrationPriceModelTypeConverter))] +public enum NewPlanUnitWithProrationPriceModelType +{ + UnitWithProration, +} + +sealed class NewPlanUnitWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewPlanUnitWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit_with_proration" => NewPlanUnitWithProrationPriceModelType.UnitWithProration, + _ => (NewPlanUnitWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewPlanUnitWithProrationPriceModelType.UnitWithProration => "unit_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + NewPlanUnitWithProrationPriceUnitWithProrationConfig, + NewPlanUnitWithProrationPriceUnitWithProrationConfigFromRaw + >) +)] +public sealed record class NewPlanUnitWithProrationPriceUnitWithProrationConfig : JsonModel +{ + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + } + + public NewPlanUnitWithProrationPriceUnitWithProrationConfig() { } + + public NewPlanUnitWithProrationPriceUnitWithProrationConfig( + NewPlanUnitWithProrationPriceUnitWithProrationConfig newPlanUnitWithProrationPriceUnitWithProrationConfig + ) + : base(newPlanUnitWithProrationPriceUnitWithProrationConfig) { } + + public NewPlanUnitWithProrationPriceUnitWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewPlanUnitWithProrationPriceUnitWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewPlanUnitWithProrationPriceUnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public NewPlanUnitWithProrationPriceUnitWithProrationConfig(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class NewPlanUnitWithProrationPriceUnitWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public NewPlanUnitWithProrationPriceUnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewPlanUnitWithProrationPriceUnitWithProrationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewPlanUnitWithProrationPriceConversionRateConfigConverter))] +public record class NewPlanUnitWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewPlanUnitWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanUnitWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewPlanUnitWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewPlanUnitWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewPlanUnitWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewPlanUnitWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewPlanUnitWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewPlanUnitWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewPlanUnitWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewPlanUnitWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewPlanUnitWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index 675264e1..00000000 --- a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanUnitWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index d68d3453..00000000 --- a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.NewPlanUnitWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanUnitWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8bc58613..00000000 --- a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewPlanUnitWithProrationPriceProperties = Orb.Models.NewPlanUnitWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.NewPlanUnitWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewPlanUnitWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewPlanUnitWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index 7e150beb..00000000 --- a/src/Orb/Models/NewPlanUnitWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewPlanUnitWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithProration = new("unit_with_proration"); - - readonly string _value = value; - - public enum Value - { - UnitWithProration, - } - - public Value Known() => - _value switch - { - "unit_with_proration" => Value.UnitWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewUsageDiscount.cs b/src/Orb/Models/NewUsageDiscount.cs index 2e50d252..67b8af8d 100644 --- a/src/Orb/Models/NewUsageDiscount.cs +++ b/src/Orb/Models/NewUsageDiscount.cs @@ -1,101 +1,72 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using NewUsageDiscountProperties = Orb.Models.NewUsageDiscountProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewUsageDiscount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewUsageDiscount : JsonModel { - public required NewUsageDiscountProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_type" + ); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } public required double UsageDiscount { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } } /// /// If set, the adjustment will apply to every price on the subscription. /// - public NewUsageDiscountProperties::AppliesToAll? AppliesToAll + public ApiEnum? AppliesToAll { get { - if (!this.Properties.TryGetValue("applies_to_all", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_all" ); } - set { this.Properties["applies_to_all"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applies_to_all", value); } } /// /// The set of item IDs to which this adjustment applies. /// - public Generic::List? AppliesToItemIDs + public IReadOnlyList? AppliesToItemIDs { get { - if (!this.Properties.TryGetValue("applies_to_item_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_item_ids"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_item_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_item_ids", value); } } /// /// The set of price IDs to which this adjustment applies. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// @@ -103,80 +74,66 @@ public required double UsageDiscount /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// A list of filters that determine which prices this adjustment will apply to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// When false, this adjustment will be applied to a single price. Otherwise, it - /// will be applied at the invoice level, possibly to multiple prices. + /// When false, this adjustment will be applied to a single price. Otherwise, + /// it will be applied at the invoice level, possibly to multiple prices. /// public bool? IsInvoiceLevel { - get + get { return JsonModel.GetNullableStruct(this.RawData, "is_invoice_level"); } + init { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// /// If set, only prices of the specified type will have the adjustment applied. /// - public NewUsageDiscountProperties::PriceType? PriceType + public ApiEnum? PriceType { get { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawData, + "price_type" ); } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_type", value); } } + /// public override void Validate() { this.AdjustmentType.Validate(); _ = this.UsageDiscount; this.AppliesToAll?.Validate(); - foreach (var item in this.AppliesToItemIDs ?? []) - { - _ = item; - } - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToItemIDs; + _ = this.AppliesToPriceIDs; _ = this.Currency; foreach (var item in this.Filters ?? []) { @@ -188,18 +145,363 @@ public override void Validate() public NewUsageDiscount() { } + public NewUsageDiscount(NewUsageDiscount newUsageDiscount) + : base(newUsageDiscount) { } + + public NewUsageDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewUsageDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + NewUsageDiscount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewUsageDiscount FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewUsageDiscountFromRaw : IFromRawJson +{ + /// + public NewUsageDiscount FromRawUnchecked(IReadOnlyDictionary rawData) => + NewUsageDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewUsageDiscountAdjustmentTypeConverter))] +public enum NewUsageDiscountAdjustmentType +{ + UsageDiscount, +} + +sealed class NewUsageDiscountAdjustmentTypeConverter : JsonConverter +{ + public override NewUsageDiscountAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_discount" => NewUsageDiscountAdjustmentType.UsageDiscount, + _ => (NewUsageDiscountAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewUsageDiscountAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewUsageDiscountAdjustmentType.UsageDiscount => "usage_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, the adjustment will apply to every price on the subscription. +/// +[JsonConverter(typeof(NewUsageDiscountAppliesToAllConverter))] +public enum NewUsageDiscountAppliesToAll +{ + True, +} + +sealed class NewUsageDiscountAppliesToAllConverter : JsonConverter +{ + public override NewUsageDiscountAppliesToAll Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + true => NewUsageDiscountAppliesToAll.True, + _ => (NewUsageDiscountAppliesToAll)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewUsageDiscountAppliesToAll value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewUsageDiscountAppliesToAll.True => true, + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class NewUsageDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public NewUsageDiscountFilter() { } + + public NewUsageDiscountFilter(NewUsageDiscountFilter newUsageDiscountFilter) + : base(newUsageDiscountFilter) { } + + public NewUsageDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewUsageDiscountFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewUsageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewUsageDiscountFilterFromRaw : IFromRawJson +{ + /// + public NewUsageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewUsageDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(NewUsageDiscountFilterFieldConverter))] +public enum NewUsageDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class NewUsageDiscountFilterFieldConverter : JsonConverter +{ + public override NewUsageDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => NewUsageDiscountFilterField.PriceID, + "item_id" => NewUsageDiscountFilterField.ItemID, + "price_type" => NewUsageDiscountFilterField.PriceType, + "currency" => NewUsageDiscountFilterField.Currency, + "pricing_unit_id" => NewUsageDiscountFilterField.PricingUnitID, + _ => (NewUsageDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewUsageDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewUsageDiscountFilterField.PriceID => "price_id", + NewUsageDiscountFilterField.ItemID => "item_id", + NewUsageDiscountFilterField.PriceType => "price_type", + NewUsageDiscountFilterField.Currency => "currency", + NewUsageDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(NewUsageDiscountFilterOperatorConverter))] +public enum NewUsageDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class NewUsageDiscountFilterOperatorConverter : JsonConverter +{ + public override NewUsageDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => NewUsageDiscountFilterOperator.Includes, + "excludes" => NewUsageDiscountFilterOperator.Excludes, + _ => (NewUsageDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewUsageDiscountFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewUsageDiscountFilterOperator.Includes => "includes", + NewUsageDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// If set, only prices of the specified type will have the adjustment applied. +/// +[JsonConverter(typeof(NewUsageDiscountPriceTypeConverter))] +public enum NewUsageDiscountPriceType +{ + Usage, + FixedInAdvance, + FixedInArrears, + Fixed, + InArrears, +} + +sealed class NewUsageDiscountPriceTypeConverter : JsonConverter +{ + public override NewUsageDiscountPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => NewUsageDiscountPriceType.Usage, + "fixed_in_advance" => NewUsageDiscountPriceType.FixedInAdvance, + "fixed_in_arrears" => NewUsageDiscountPriceType.FixedInArrears, + "fixed" => NewUsageDiscountPriceType.Fixed, + "in_arrears" => NewUsageDiscountPriceType.InArrears, + _ => (NewUsageDiscountPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewUsageDiscountPriceType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + NewUsageDiscountPriceType.Usage => "usage", + NewUsageDiscountPriceType.FixedInAdvance => "fixed_in_advance", + NewUsageDiscountPriceType.FixedInArrears => "fixed_in_arrears", + NewUsageDiscountPriceType.Fixed => "fixed", + NewUsageDiscountPriceType.InArrears => "in_arrears", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/NewUsageDiscountProperties/AdjustmentType.cs b/src/Orb/Models/NewUsageDiscountProperties/AdjustmentType.cs deleted file mode 100644 index 844ba144..00000000 --- a/src/Orb/Models/NewUsageDiscountProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewUsageDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType UsageDiscount = new("usage_discount"); - - readonly string _value = value; - - public enum Value - { - UsageDiscount, - } - - public Value Known() => - _value switch - { - "usage_discount" => Value.UsageDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewUsageDiscountProperties/AppliesToAll.cs b/src/Orb/Models/NewUsageDiscountProperties/AppliesToAll.cs deleted file mode 100644 index 3ac4d103..00000000 --- a/src/Orb/Models/NewUsageDiscountProperties/AppliesToAll.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewUsageDiscountProperties; - -/// -/// If set, the adjustment will apply to every price on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AppliesToAll(bool value) : Orb::IEnum -{ - public static readonly AppliesToAll True = new(true); - - readonly bool _value = value; - - public enum Value - { - True, - } - - public Value Known() => - _value switch - { - true => Value.True, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public bool Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AppliesToAll FromRaw(bool value) - { - return new(value); - } -} diff --git a/src/Orb/Models/NewUsageDiscountProperties/PriceType.cs b/src/Orb/Models/NewUsageDiscountProperties/PriceType.cs deleted file mode 100644 index 0f68f3a0..00000000 --- a/src/Orb/Models/NewUsageDiscountProperties/PriceType.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.NewUsageDiscountProperties; - -/// -/// If set, only prices of the specified type will have the adjustment applied. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType Usage = new("usage"); - - public static readonly PriceType FixedInAdvance = new("fixed_in_advance"); - - public static readonly PriceType FixedInArrears = new("fixed_in_arrears"); - - public static readonly PriceType Fixed = new("fixed"); - - public static readonly PriceType InArrears = new("in_arrears"); - - readonly string _value = value; - - public enum Value - { - Usage, - FixedInAdvance, - FixedInArrears, - Fixed, - InArrears, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - "fixed_in_advance" => Value.FixedInAdvance, - "fixed_in_arrears" => Value.FixedInArrears, - "fixed" => Value.Fixed, - "in_arrears" => Value.InArrears, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/OtherSubLineItem.cs b/src/Orb/Models/OtherSubLineItem.cs index 2be92aa6..c3aef75f 100644 --- a/src/Orb/Models/OtherSubLineItem.cs +++ b/src/Orb/Models/OtherSubLineItem.cs @@ -1,91 +1,57 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using OtherSubLineItemProperties = Orb.Models.OtherSubLineItemProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class OtherSubLineItem : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class OtherSubLineItem : JsonModel { /// /// The total amount for this sub line item. /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } public required SubLineItemGrouping? Grouping { - get - { - if (!this.Properties.TryGetValue("grouping", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["grouping"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } } public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } public required double Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } - public required OtherSubLineItemProperties::Type Type + public required ApiEnum Type { get { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "type", value); } } + /// public override void Validate() { _ = this.Amount; @@ -97,18 +63,75 @@ public override void Validate() public OtherSubLineItem() { } + public OtherSubLineItem(OtherSubLineItem otherSubLineItem) + : base(otherSubLineItem) { } + + public OtherSubLineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - OtherSubLineItem(Generic::Dictionary properties) + [SetsRequiredMembers] + OtherSubLineItem(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static OtherSubLineItem FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class OtherSubLineItemFromRaw : IFromRawJson +{ + /// + public OtherSubLineItem FromRawUnchecked(IReadOnlyDictionary rawData) => + OtherSubLineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(OtherSubLineItemTypeConverter))] +public enum OtherSubLineItemType +{ + Null, +} + +sealed class OtherSubLineItemTypeConverter : JsonConverter +{ + public override OtherSubLineItemType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "'null'" => OtherSubLineItemType.Null, + _ => (OtherSubLineItemType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + OtherSubLineItemType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + OtherSubLineItemType.Null => "'null'", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/OtherSubLineItemProperties/Type.cs b/src/Orb/Models/OtherSubLineItemProperties/Type.cs deleted file mode 100644 index c779c5ca..00000000 --- a/src/Orb/Models/OtherSubLineItemProperties/Type.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.OtherSubLineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Null = new("'null'"); - - readonly string _value = value; - - public enum Value - { - Null, - } - - public Value Known() => - _value switch - { - "'null'" => Value.Null, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PackageConfig.cs b/src/Orb/Models/PackageConfig.cs index 2dc191bf..ec5ad705 100644 --- a/src/Orb/Models/PackageConfig.cs +++ b/src/Orb/Models/PackageConfig.cs @@ -1,53 +1,38 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PackageConfig : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for package pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PackageConfig : JsonModel { /// /// A currency amount to rate usage by /// public required string PackageAmount { - get - { - if (!this.Properties.TryGetValue("package_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "package_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("package_amount"); - } - set { this.Properties["package_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "package_amount"); } + init { JsonModel.Set(this._rawData, "package_amount", value); } } /// - /// An integer amount to represent package size. For example, 1000 here would divide - /// usage by 1000 before multiplying by package_amount in rating + /// An integer amount to represent package size. For example, 1000 here would + /// divide usage by 1000 before multiplying by package_amount in rating /// public required long PackageSize { - get - { - if (!this.Properties.TryGetValue("package_size", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "package_size", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["package_size"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } } + /// public override void Validate() { _ = this.PackageAmount; @@ -56,18 +41,32 @@ public override void Validate() public PackageConfig() { } + public PackageConfig(PackageConfig packageConfig) + : base(packageConfig) { } + + public PackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PackageConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + PackageConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static PackageConfig FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static PackageConfig FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class PackageConfigFromRaw : IFromRawJson +{ + /// + public PackageConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + PackageConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/PaginationMetadata.cs b/src/Orb/Models/PaginationMetadata.cs index 9c77c7b1..8fe9f28c 100644 --- a/src/Orb/Models/PaginationMetadata.cs +++ b/src/Orb/Models/PaginationMetadata.cs @@ -1,45 +1,28 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PaginationMetadata : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PaginationMetadata : JsonModel { public required bool HasMore { - get - { - if (!this.Properties.TryGetValue("has_more", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "has_more", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["has_more"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "has_more"); } + init { JsonModel.Set(this._rawData, "has_more", value); } } public required string? NextCursor { - get - { - if (!this.Properties.TryGetValue("next_cursor", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "next_cursor", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["next_cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "next_cursor"); } + init { JsonModel.Set(this._rawData, "next_cursor", value); } } + /// public override void Validate() { _ = this.HasMore; @@ -48,18 +31,34 @@ public override void Validate() public PaginationMetadata() { } + public PaginationMetadata(PaginationMetadata paginationMetadata) + : base(paginationMetadata) { } + + public PaginationMetadata(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PaginationMetadata(Generic::Dictionary properties) + [SetsRequiredMembers] + PaginationMetadata(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PaginationMetadata FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class PaginationMetadataFromRaw : IFromRawJson +{ + /// + public PaginationMetadata FromRawUnchecked(IReadOnlyDictionary rawData) => + PaginationMetadata.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/PerPriceCost.cs b/src/Orb/Models/PerPriceCost.cs index 0a0dd775..7ce06cc4 100644 --- a/src/Orb/Models/PerPriceCost.cs +++ b/src/Orb/Models/PerPriceCost.cs @@ -1,29 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PerPriceCost : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PerPriceCost : JsonModel { /// /// The price object /// public required Price Price { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("price", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price"); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } } /// @@ -31,18 +24,8 @@ public required Price Price /// public required string PriceID { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } } /// @@ -50,18 +33,8 @@ public required string PriceID /// public required string Subtotal { - get - { - if (!this.Properties.TryGetValue("subtotal", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subtotal", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("subtotal"); - } - set { this.Properties["subtotal"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } } /// @@ -69,15 +42,8 @@ public required string Subtotal /// public required string Total { - get - { - if (!this.Properties.TryGetValue("total", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("total", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("total"); - } - set { this.Properties["total"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } } /// @@ -85,16 +51,11 @@ public required string Total /// public double? Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } + /// public override void Validate() { this.Price.Validate(); @@ -106,18 +67,32 @@ public override void Validate() public PerPriceCost() { } + public PerPriceCost(PerPriceCost perPriceCost) + : base(perPriceCost) { } + + public PerPriceCost(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PerPriceCost(Generic::Dictionary properties) + [SetsRequiredMembers] + PerPriceCost(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static PerPriceCost FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static PerPriceCost FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class PerPriceCostFromRaw : IFromRawJson +{ + /// + public PerPriceCost FromRawUnchecked(IReadOnlyDictionary rawData) => + PerPriceCost.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/PercentageDiscount.cs b/src/Orb/Models/PercentageDiscount.cs index dec2531e..a70099c7 100644 --- a/src/Orb/Models/PercentageDiscount.cs +++ b/src/Orb/Models/PercentageDiscount.cs @@ -1,111 +1,79 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PercentageDiscountProperties = Orb.Models.PercentageDiscountProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PercentageDiscount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PercentageDiscount : JsonModel { - public required PercentageDiscountProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// - /// Only available if discount_type is `percentage`. This is a number between 0 - /// and 1. + /// Only available if discount_type is `percentage`. This is a number between + /// 0 and 1. /// - public required double PercentageDiscount1 + public required double PercentageDiscountValue { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } } /// /// List of price_ids that this discount applies to. For plan/plan phase discounts, /// this can be a subset of prices. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this discount to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } public string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } + /// public override void Validate() { this.DiscountType.Validate(); - _ = this.PercentageDiscount1; - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.PercentageDiscountValue; + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters ?? []) { item.Validate(); @@ -115,18 +83,266 @@ public override void Validate() public PercentageDiscount() { } + public PercentageDiscount(PercentageDiscount percentageDiscount) + : base(percentageDiscount) { } + + public PercentageDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PercentageDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + PercentageDiscount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PercentageDiscount FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentageDiscountFromRaw : IFromRawJson +{ + /// + public PercentageDiscount FromRawUnchecked(IReadOnlyDictionary rawData) => + PercentageDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PercentageDiscountDiscountTypeConverter))] +public enum PercentageDiscountDiscountType +{ + Percentage, +} + +sealed class PercentageDiscountDiscountTypeConverter : JsonConverter +{ + public override PercentageDiscountDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage" => PercentageDiscountDiscountType.Percentage, + _ => (PercentageDiscountDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentageDiscountDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentageDiscountDiscountType.Percentage => "percentage", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PercentageDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PercentageDiscountFilter() { } + + public PercentageDiscountFilter(PercentageDiscountFilter percentageDiscountFilter) + : base(percentageDiscountFilter) { } + + public PercentageDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentageDiscountFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PercentageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentageDiscountFilterFromRaw : IFromRawJson +{ + /// + public PercentageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PercentageDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PercentageDiscountFilterFieldConverter))] +public enum PercentageDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PercentageDiscountFilterFieldConverter : JsonConverter +{ + public override PercentageDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PercentageDiscountFilterField.PriceID, + "item_id" => PercentageDiscountFilterField.ItemID, + "price_type" => PercentageDiscountFilterField.PriceType, + "currency" => PercentageDiscountFilterField.Currency, + "pricing_unit_id" => PercentageDiscountFilterField.PricingUnitID, + _ => (PercentageDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentageDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentageDiscountFilterField.PriceID => "price_id", + PercentageDiscountFilterField.ItemID => "item_id", + PercentageDiscountFilterField.PriceType => "price_type", + PercentageDiscountFilterField.Currency => "currency", + PercentageDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PercentageDiscountFilterOperatorConverter))] +public enum PercentageDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class PercentageDiscountFilterOperatorConverter + : JsonConverter +{ + public override PercentageDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PercentageDiscountFilterOperator.Includes, + "excludes" => PercentageDiscountFilterOperator.Excludes, + _ => (PercentageDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentageDiscountFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PercentageDiscountFilterOperator.Includes => "includes", + PercentageDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PercentageDiscountInterval.cs b/src/Orb/Models/PercentageDiscountInterval.cs index 1b338095..a1bd9c13 100644 --- a/src/Orb/Models/PercentageDiscountInterval.cs +++ b/src/Orb/Models/PercentageDiscountInterval.cs @@ -1,146 +1,98 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PercentageDiscountIntervalProperties = Orb.Models.PercentageDiscountIntervalProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PercentageDiscountInterval - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PercentageDiscountInterval : JsonModel { /// /// The price interval ids that this discount interval applies to. /// - public required Generic::List AppliesToPriceIntervalIDs + public required IReadOnlyList AppliesToPriceIntervalIDs { get { - if ( - !this.Properties.TryGetValue( - "applies_to_price_interval_ids", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_interval_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_interval_ids"); - } - set - { - this.Properties["applies_to_price_interval_ids"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "applies_to_price_interval_ids" + ); } + init { JsonModel.Set(this._rawData, "applies_to_price_interval_ids", value); } } - public required PercentageDiscountIntervalProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "discount_type"); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// /// The end date of the discount interval. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// /// The filters that determine which prices this discount interval applies to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// Only available if discount_type is `percentage`.This is a number between 0 - /// and 1. + /// Only available if discount_type is `percentage`.This is a number between + /// 0 and 1. /// public required double PercentageDiscount { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } } /// /// The start date of the discount interval. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } + /// public override void Validate() { - foreach (var item in this.AppliesToPriceIntervalIDs) - { - _ = item; - } + _ = this.AppliesToPriceIntervalIDs; this.DiscountType.Validate(); _ = this.EndDate; foreach (var item in this.Filters) @@ -153,18 +105,272 @@ public override void Validate() public PercentageDiscountInterval() { } + public PercentageDiscountInterval(PercentageDiscountInterval percentageDiscountInterval) + : base(percentageDiscountInterval) { } + + public PercentageDiscountInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PercentageDiscountInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + PercentageDiscountInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PercentageDiscountInterval FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentageDiscountIntervalFromRaw : IFromRawJson +{ + /// + public PercentageDiscountInterval FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PercentageDiscountInterval.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PercentageDiscountIntervalDiscountTypeConverter))] +public enum PercentageDiscountIntervalDiscountType +{ + Percentage, +} + +sealed class PercentageDiscountIntervalDiscountTypeConverter + : JsonConverter +{ + public override PercentageDiscountIntervalDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage" => PercentageDiscountIntervalDiscountType.Percentage, + _ => (PercentageDiscountIntervalDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentageDiscountIntervalDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentageDiscountIntervalDiscountType.Percentage => "percentage", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PercentageDiscountIntervalFilter, + PercentageDiscountIntervalFilterFromRaw + >) +)] +public sealed record class PercentageDiscountIntervalFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PercentageDiscountIntervalFilter() { } + + public PercentageDiscountIntervalFilter( + PercentageDiscountIntervalFilter percentageDiscountIntervalFilter + ) + : base(percentageDiscountIntervalFilter) { } + + public PercentageDiscountIntervalFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentageDiscountIntervalFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PercentageDiscountIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentageDiscountIntervalFilterFromRaw : IFromRawJson +{ + /// + public PercentageDiscountIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PercentageDiscountIntervalFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PercentageDiscountIntervalFilterFieldConverter))] +public enum PercentageDiscountIntervalFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PercentageDiscountIntervalFilterFieldConverter + : JsonConverter +{ + public override PercentageDiscountIntervalFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PercentageDiscountIntervalFilterField.PriceID, + "item_id" => PercentageDiscountIntervalFilterField.ItemID, + "price_type" => PercentageDiscountIntervalFilterField.PriceType, + "currency" => PercentageDiscountIntervalFilterField.Currency, + "pricing_unit_id" => PercentageDiscountIntervalFilterField.PricingUnitID, + _ => (PercentageDiscountIntervalFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentageDiscountIntervalFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentageDiscountIntervalFilterField.PriceID => "price_id", + PercentageDiscountIntervalFilterField.ItemID => "item_id", + PercentageDiscountIntervalFilterField.PriceType => "price_type", + PercentageDiscountIntervalFilterField.Currency => "currency", + PercentageDiscountIntervalFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PercentageDiscountIntervalFilterOperatorConverter))] +public enum PercentageDiscountIntervalFilterOperator +{ + Includes, + Excludes, +} + +sealed class PercentageDiscountIntervalFilterOperatorConverter + : JsonConverter +{ + public override PercentageDiscountIntervalFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PercentageDiscountIntervalFilterOperator.Includes, + "excludes" => PercentageDiscountIntervalFilterOperator.Excludes, + _ => (PercentageDiscountIntervalFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentageDiscountIntervalFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PercentageDiscountIntervalFilterOperator.Includes => "includes", + PercentageDiscountIntervalFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PercentageDiscountIntervalProperties/DiscountType.cs b/src/Orb/Models/PercentageDiscountIntervalProperties/DiscountType.cs deleted file mode 100644 index 190260a7..00000000 --- a/src/Orb/Models/PercentageDiscountIntervalProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PercentageDiscountIntervalProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - readonly string _value = value; - - public enum Value - { - Percentage, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PercentageDiscountProperties/DiscountType.cs b/src/Orb/Models/PercentageDiscountProperties/DiscountType.cs deleted file mode 100644 index 0e16ce51..00000000 --- a/src/Orb/Models/PercentageDiscountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PercentageDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - readonly string _value = value; - - public enum Value - { - Percentage, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PlanPhaseAmountDiscountAdjustment.cs b/src/Orb/Models/PlanPhaseAmountDiscountAdjustment.cs index 52cb900d..6e592824 100644 --- a/src/Orb/Models/PlanPhaseAmountDiscountAdjustment.cs +++ b/src/Orb/Models/PlanPhaseAmountDiscountAdjustment.cs @@ -1,131 +1,85 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanPhaseAmountDiscountAdjustmentProperties = Orb.Models.PlanPhaseAmountDiscountAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhaseAmountDiscountAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + PlanPhaseAmountDiscountAdjustment, + PlanPhaseAmountDiscountAdjustmentFromRaw + >) +)] +public sealed record class PlanPhaseAmountDiscountAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required PlanPhaseAmountDiscountAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// - /// The amount by which to discount the prices this adjustment applies to in a given - /// billing period. + /// The amount by which to discount the prices this adjustment applies to in a + /// given billing period. /// public required string AmountDiscount { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount_discount"); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -133,20 +87,8 @@ public required bool IsInvoiceLevel /// public required long? PlanPhaseOrder { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } } /// @@ -154,57 +96,27 @@ public required long? PlanPhaseOrder /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); _ = this.AmountDiscount; - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -215,20 +127,281 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public PlanPhaseAmountDiscountAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseAmountDiscountAdjustment( + PlanPhaseAmountDiscountAdjustment planPhaseAmountDiscountAdjustment + ) + : base(planPhaseAmountDiscountAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseAmountDiscountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhaseAmountDiscountAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + PlanPhaseAmountDiscountAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanPhaseAmountDiscountAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseAmountDiscountAdjustmentFromRaw : IFromRawJson +{ + /// + public PlanPhaseAmountDiscountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseAmountDiscountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanPhaseAmountDiscountAdjustmentAdjustmentTypeConverter))] +public enum PlanPhaseAmountDiscountAdjustmentAdjustmentType +{ + AmountDiscount, +} + +sealed class PlanPhaseAmountDiscountAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override PlanPhaseAmountDiscountAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "amount_discount" => PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount, + _ => (PlanPhaseAmountDiscountAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseAmountDiscountAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseAmountDiscountAdjustmentAdjustmentType.AmountDiscount => "amount_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PlanPhaseAmountDiscountAdjustmentFilter, + PlanPhaseAmountDiscountAdjustmentFilterFromRaw + >) +)] +public sealed record class PlanPhaseAmountDiscountAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PlanPhaseAmountDiscountAdjustmentFilter() { } + + public PlanPhaseAmountDiscountAdjustmentFilter( + PlanPhaseAmountDiscountAdjustmentFilter planPhaseAmountDiscountAdjustmentFilter + ) + : base(planPhaseAmountDiscountAdjustmentFilter) { } + + public PlanPhaseAmountDiscountAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPhaseAmountDiscountAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPhaseAmountDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseAmountDiscountAdjustmentFilterFromRaw + : IFromRawJson +{ + /// + public PlanPhaseAmountDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseAmountDiscountAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PlanPhaseAmountDiscountAdjustmentFilterFieldConverter))] +public enum PlanPhaseAmountDiscountAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PlanPhaseAmountDiscountAdjustmentFilterFieldConverter + : JsonConverter +{ + public override PlanPhaseAmountDiscountAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PlanPhaseAmountDiscountAdjustmentFilterField.PriceID, + "item_id" => PlanPhaseAmountDiscountAdjustmentFilterField.ItemID, + "price_type" => PlanPhaseAmountDiscountAdjustmentFilterField.PriceType, + "currency" => PlanPhaseAmountDiscountAdjustmentFilterField.Currency, + "pricing_unit_id" => PlanPhaseAmountDiscountAdjustmentFilterField.PricingUnitID, + _ => (PlanPhaseAmountDiscountAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseAmountDiscountAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseAmountDiscountAdjustmentFilterField.PriceID => "price_id", + PlanPhaseAmountDiscountAdjustmentFilterField.ItemID => "item_id", + PlanPhaseAmountDiscountAdjustmentFilterField.PriceType => "price_type", + PlanPhaseAmountDiscountAdjustmentFilterField.Currency => "currency", + PlanPhaseAmountDiscountAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PlanPhaseAmountDiscountAdjustmentFilterOperatorConverter))] +public enum PlanPhaseAmountDiscountAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class PlanPhaseAmountDiscountAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override PlanPhaseAmountDiscountAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes, + "excludes" => PlanPhaseAmountDiscountAdjustmentFilterOperator.Excludes, + _ => (PlanPhaseAmountDiscountAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseAmountDiscountAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseAmountDiscountAdjustmentFilterOperator.Includes => "includes", + PlanPhaseAmountDiscountAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PlanPhaseAmountDiscountAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/PlanPhaseAmountDiscountAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 8bc3a73d..00000000 --- a/src/Orb/Models/PlanPhaseAmountDiscountAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PlanPhaseAmountDiscountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType AmountDiscount = new("amount_discount"); - - readonly string _value = value; - - public enum Value - { - AmountDiscount, - } - - public Value Known() => - _value switch - { - "amount_discount" => Value.AmountDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PlanPhaseMaximumAdjustment.cs b/src/Orb/Models/PlanPhaseMaximumAdjustment.cs index 27c037c3..2f7a5102 100644 --- a/src/Orb/Models/PlanPhaseMaximumAdjustment.cs +++ b/src/Orb/Models/PlanPhaseMaximumAdjustment.cs @@ -1,131 +1,82 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanPhaseMaximumAdjustmentProperties = Orb.Models.PlanPhaseMaximumAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhaseMaximumAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PlanPhaseMaximumAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required PlanPhaseMaximumAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// - /// The maximum amount to charge in a given billing period for the prices this adjustment - /// applies to. + /// The maximum amount to charge in a given billing period for the prices this + /// adjustment applies to. /// public required string MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("maximum_amount"); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// @@ -133,20 +84,8 @@ public required string MaximumAmount /// public required long? PlanPhaseOrder { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } } /// @@ -154,56 +93,26 @@ public required long? PlanPhaseOrder /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -215,20 +124,278 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public PlanPhaseMaximumAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseMaximumAdjustment(PlanPhaseMaximumAdjustment planPhaseMaximumAdjustment) + : base(planPhaseMaximumAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseMaximumAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhaseMaximumAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + PlanPhaseMaximumAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanPhaseMaximumAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseMaximumAdjustmentFromRaw : IFromRawJson +{ + /// + public PlanPhaseMaximumAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseMaximumAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanPhaseMaximumAdjustmentAdjustmentTypeConverter))] +public enum PlanPhaseMaximumAdjustmentAdjustmentType +{ + Maximum, +} + +sealed class PlanPhaseMaximumAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override PlanPhaseMaximumAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "maximum" => PlanPhaseMaximumAdjustmentAdjustmentType.Maximum, + _ => (PlanPhaseMaximumAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseMaximumAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseMaximumAdjustmentAdjustmentType.Maximum => "maximum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PlanPhaseMaximumAdjustmentFilter, + PlanPhaseMaximumAdjustmentFilterFromRaw + >) +)] +public sealed record class PlanPhaseMaximumAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PlanPhaseMaximumAdjustmentFilter() { } + + public PlanPhaseMaximumAdjustmentFilter( + PlanPhaseMaximumAdjustmentFilter planPhaseMaximumAdjustmentFilter + ) + : base(planPhaseMaximumAdjustmentFilter) { } + + public PlanPhaseMaximumAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPhaseMaximumAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPhaseMaximumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseMaximumAdjustmentFilterFromRaw : IFromRawJson +{ + /// + public PlanPhaseMaximumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseMaximumAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PlanPhaseMaximumAdjustmentFilterFieldConverter))] +public enum PlanPhaseMaximumAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PlanPhaseMaximumAdjustmentFilterFieldConverter + : JsonConverter +{ + public override PlanPhaseMaximumAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PlanPhaseMaximumAdjustmentFilterField.PriceID, + "item_id" => PlanPhaseMaximumAdjustmentFilterField.ItemID, + "price_type" => PlanPhaseMaximumAdjustmentFilterField.PriceType, + "currency" => PlanPhaseMaximumAdjustmentFilterField.Currency, + "pricing_unit_id" => PlanPhaseMaximumAdjustmentFilterField.PricingUnitID, + _ => (PlanPhaseMaximumAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseMaximumAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseMaximumAdjustmentFilterField.PriceID => "price_id", + PlanPhaseMaximumAdjustmentFilterField.ItemID => "item_id", + PlanPhaseMaximumAdjustmentFilterField.PriceType => "price_type", + PlanPhaseMaximumAdjustmentFilterField.Currency => "currency", + PlanPhaseMaximumAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PlanPhaseMaximumAdjustmentFilterOperatorConverter))] +public enum PlanPhaseMaximumAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class PlanPhaseMaximumAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override PlanPhaseMaximumAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PlanPhaseMaximumAdjustmentFilterOperator.Includes, + "excludes" => PlanPhaseMaximumAdjustmentFilterOperator.Excludes, + _ => (PlanPhaseMaximumAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseMaximumAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseMaximumAdjustmentFilterOperator.Includes => "includes", + PlanPhaseMaximumAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PlanPhaseMaximumAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/PlanPhaseMaximumAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 176b4fdd..00000000 --- a/src/Orb/Models/PlanPhaseMaximumAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PlanPhaseMaximumAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType Maximum = new("maximum"); - - readonly string _value = value; - - public enum Value - { - Maximum, - } - - public Value Known() => - _value switch - { - "maximum" => Value.Maximum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PlanPhaseMinimumAdjustment.cs b/src/Orb/Models/PlanPhaseMinimumAdjustment.cs index d0f7b63f..7fc424d0 100644 --- a/src/Orb/Models/PlanPhaseMinimumAdjustment.cs +++ b/src/Orb/Models/PlanPhaseMinimumAdjustment.cs @@ -1,111 +1,72 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanPhaseMinimumAdjustmentProperties = Orb.Models.PlanPhaseMinimumAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhaseMinimumAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PlanPhaseMinimumAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required PlanPhaseMinimumAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -113,38 +74,18 @@ public required bool IsInvoiceLevel /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } /// - /// The minimum amount to charge in a given billing period for the prices this adjustment - /// applies to. + /// The minimum amount to charge in a given billing period for the prices this + /// adjustment applies to. /// public required string MinimumAmount { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("minimum_amount"); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } } /// @@ -152,20 +93,8 @@ public required string MinimumAmount /// public required long? PlanPhaseOrder { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } } /// @@ -173,56 +102,26 @@ public required long? PlanPhaseOrder /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -235,20 +134,278 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public PlanPhaseMinimumAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseMinimumAdjustment(PlanPhaseMinimumAdjustment planPhaseMinimumAdjustment) + : base(planPhaseMinimumAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseMinimumAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhaseMinimumAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + PlanPhaseMinimumAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanPhaseMinimumAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseMinimumAdjustmentFromRaw : IFromRawJson +{ + /// + public PlanPhaseMinimumAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseMinimumAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanPhaseMinimumAdjustmentAdjustmentTypeConverter))] +public enum PlanPhaseMinimumAdjustmentAdjustmentType +{ + Minimum, +} + +sealed class PlanPhaseMinimumAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override PlanPhaseMinimumAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "minimum" => PlanPhaseMinimumAdjustmentAdjustmentType.Minimum, + _ => (PlanPhaseMinimumAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseMinimumAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseMinimumAdjustmentAdjustmentType.Minimum => "minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PlanPhaseMinimumAdjustmentFilter, + PlanPhaseMinimumAdjustmentFilterFromRaw + >) +)] +public sealed record class PlanPhaseMinimumAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PlanPhaseMinimumAdjustmentFilter() { } + + public PlanPhaseMinimumAdjustmentFilter( + PlanPhaseMinimumAdjustmentFilter planPhaseMinimumAdjustmentFilter + ) + : base(planPhaseMinimumAdjustmentFilter) { } + + public PlanPhaseMinimumAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPhaseMinimumAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPhaseMinimumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseMinimumAdjustmentFilterFromRaw : IFromRawJson +{ + /// + public PlanPhaseMinimumAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseMinimumAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PlanPhaseMinimumAdjustmentFilterFieldConverter))] +public enum PlanPhaseMinimumAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PlanPhaseMinimumAdjustmentFilterFieldConverter + : JsonConverter +{ + public override PlanPhaseMinimumAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PlanPhaseMinimumAdjustmentFilterField.PriceID, + "item_id" => PlanPhaseMinimumAdjustmentFilterField.ItemID, + "price_type" => PlanPhaseMinimumAdjustmentFilterField.PriceType, + "currency" => PlanPhaseMinimumAdjustmentFilterField.Currency, + "pricing_unit_id" => PlanPhaseMinimumAdjustmentFilterField.PricingUnitID, + _ => (PlanPhaseMinimumAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseMinimumAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseMinimumAdjustmentFilterField.PriceID => "price_id", + PlanPhaseMinimumAdjustmentFilterField.ItemID => "item_id", + PlanPhaseMinimumAdjustmentFilterField.PriceType => "price_type", + PlanPhaseMinimumAdjustmentFilterField.Currency => "currency", + PlanPhaseMinimumAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PlanPhaseMinimumAdjustmentFilterOperatorConverter))] +public enum PlanPhaseMinimumAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class PlanPhaseMinimumAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override PlanPhaseMinimumAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PlanPhaseMinimumAdjustmentFilterOperator.Includes, + "excludes" => PlanPhaseMinimumAdjustmentFilterOperator.Excludes, + _ => (PlanPhaseMinimumAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseMinimumAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseMinimumAdjustmentFilterOperator.Includes => "includes", + PlanPhaseMinimumAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PlanPhaseMinimumAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/PlanPhaseMinimumAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 9cf4a9a9..00000000 --- a/src/Orb/Models/PlanPhaseMinimumAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PlanPhaseMinimumAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType Minimum = new("minimum"); - - readonly string _value = value; - - public enum Value - { - Minimum, - } - - public Value Known() => - _value switch - { - "minimum" => Value.Minimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PlanPhasePercentageDiscountAdjustment.cs b/src/Orb/Models/PlanPhasePercentageDiscountAdjustment.cs index fada7391..34f9daa2 100644 --- a/src/Orb/Models/PlanPhasePercentageDiscountAdjustment.cs +++ b/src/Orb/Models/PlanPhasePercentageDiscountAdjustment.cs @@ -1,111 +1,78 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanPhasePercentageDiscountAdjustmentProperties = Orb.Models.PlanPhasePercentageDiscountAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhasePercentageDiscountAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + PlanPhasePercentageDiscountAdjustment, + PlanPhasePercentageDiscountAdjustmentFromRaw + >) +)] +public sealed record class PlanPhasePercentageDiscountAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required PlanPhasePercentageDiscountAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum< + string, + PlanPhasePercentageDiscountAdjustmentAdjustmentType + > AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -114,20 +81,8 @@ public required bool IsInvoiceLevel /// public required double PercentageDiscount { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } } /// @@ -135,20 +90,8 @@ public required double PercentageDiscount /// public required long? PlanPhaseOrder { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } } /// @@ -156,56 +99,26 @@ public required long? PlanPhaseOrder /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -217,20 +130,286 @@ public override void Validate() _ = this.ReplacesAdjustmentID; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public PlanPhasePercentageDiscountAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhasePercentageDiscountAdjustment( + PlanPhasePercentageDiscountAdjustment planPhasePercentageDiscountAdjustment + ) + : base(planPhasePercentageDiscountAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhasePercentageDiscountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhasePercentageDiscountAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + PlanPhasePercentageDiscountAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanPhasePercentageDiscountAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhasePercentageDiscountAdjustmentFromRaw + : IFromRawJson +{ + /// + public PlanPhasePercentageDiscountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhasePercentageDiscountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanPhasePercentageDiscountAdjustmentAdjustmentTypeConverter))] +public enum PlanPhasePercentageDiscountAdjustmentAdjustmentType +{ + PercentageDiscount, +} + +sealed class PlanPhasePercentageDiscountAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override PlanPhasePercentageDiscountAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage_discount" => + PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount, + _ => (PlanPhasePercentageDiscountAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhasePercentageDiscountAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhasePercentageDiscountAdjustmentAdjustmentType.PercentageDiscount => + "percentage_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PlanPhasePercentageDiscountAdjustmentFilter, + PlanPhasePercentageDiscountAdjustmentFilterFromRaw + >) +)] +public sealed record class PlanPhasePercentageDiscountAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PlanPhasePercentageDiscountAdjustmentFilter() { } + + public PlanPhasePercentageDiscountAdjustmentFilter( + PlanPhasePercentageDiscountAdjustmentFilter planPhasePercentageDiscountAdjustmentFilter + ) + : base(planPhasePercentageDiscountAdjustmentFilter) { } + + public PlanPhasePercentageDiscountAdjustmentFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPhasePercentageDiscountAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPhasePercentageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhasePercentageDiscountAdjustmentFilterFromRaw + : IFromRawJson +{ + /// + public PlanPhasePercentageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhasePercentageDiscountAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PlanPhasePercentageDiscountAdjustmentFilterFieldConverter))] +public enum PlanPhasePercentageDiscountAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PlanPhasePercentageDiscountAdjustmentFilterFieldConverter + : JsonConverter +{ + public override PlanPhasePercentageDiscountAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PlanPhasePercentageDiscountAdjustmentFilterField.PriceID, + "item_id" => PlanPhasePercentageDiscountAdjustmentFilterField.ItemID, + "price_type" => PlanPhasePercentageDiscountAdjustmentFilterField.PriceType, + "currency" => PlanPhasePercentageDiscountAdjustmentFilterField.Currency, + "pricing_unit_id" => PlanPhasePercentageDiscountAdjustmentFilterField.PricingUnitID, + _ => (PlanPhasePercentageDiscountAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhasePercentageDiscountAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhasePercentageDiscountAdjustmentFilterField.PriceID => "price_id", + PlanPhasePercentageDiscountAdjustmentFilterField.ItemID => "item_id", + PlanPhasePercentageDiscountAdjustmentFilterField.PriceType => "price_type", + PlanPhasePercentageDiscountAdjustmentFilterField.Currency => "currency", + PlanPhasePercentageDiscountAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PlanPhasePercentageDiscountAdjustmentFilterOperatorConverter))] +public enum PlanPhasePercentageDiscountAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class PlanPhasePercentageDiscountAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override PlanPhasePercentageDiscountAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes, + "excludes" => PlanPhasePercentageDiscountAdjustmentFilterOperator.Excludes, + _ => (PlanPhasePercentageDiscountAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhasePercentageDiscountAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhasePercentageDiscountAdjustmentFilterOperator.Includes => "includes", + PlanPhasePercentageDiscountAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PlanPhasePercentageDiscountAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/PlanPhasePercentageDiscountAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 288d66ae..00000000 --- a/src/Orb/Models/PlanPhasePercentageDiscountAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PlanPhasePercentageDiscountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType PercentageDiscount = new("percentage_discount"); - - readonly string _value = value; - - public enum Value - { - PercentageDiscount, - } - - public Value Known() => - _value switch - { - "percentage_discount" => Value.PercentageDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PlanPhaseUsageDiscountAdjustment.cs b/src/Orb/Models/PlanPhaseUsageDiscountAdjustment.cs index 45fd3b1d..36b41f16 100644 --- a/src/Orb/Models/PlanPhaseUsageDiscountAdjustment.cs +++ b/src/Orb/Models/PlanPhaseUsageDiscountAdjustment.cs @@ -1,111 +1,75 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanPhaseUsageDiscountAdjustmentProperties = Orb.Models.PlanPhaseUsageDiscountAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhaseUsageDiscountAdjustment - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + PlanPhaseUsageDiscountAdjustment, + PlanPhaseUsageDiscountAdjustmentFromRaw + >) +)] +public sealed record class PlanPhaseUsageDiscountAdjustment : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } - public required PlanPhaseUsageDiscountAdjustmentProperties::AdjustmentType AdjustmentType + public required ApiEnum AdjustmentType { get { - if (!this.Properties.TryGetValue("adjustment_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "adjustment_type"); } - set { this.Properties["adjustment_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "adjustment_type", value); } } /// /// The price IDs that this adjustment applies to. /// - public required Generic::List AppliesToPriceIDs + [System::Obsolete("deprecated")] + public required IReadOnlyList AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_ids"); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this adjustment to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// - /// True for adjustments that apply to an entire invocice, false for adjustments + /// True for adjustments that apply to an entire invoice, false for adjustments /// that apply to only one price. /// public required bool IsInvoiceLevel { - get - { - if (!this.Properties.TryGetValue("is_invoice_level", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "is_invoice_level", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["is_invoice_level"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "is_invoice_level"); } + init { JsonModel.Set(this._rawData, "is_invoice_level", value); } } /// @@ -113,20 +77,8 @@ public required bool IsInvoiceLevel /// public required long? PlanPhaseOrder { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } } /// @@ -134,46 +86,18 @@ public required long? PlanPhaseOrder /// public required string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "reason", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// - /// The adjustment id this adjustment replaces. This adjustment will take the place - /// of the replaced adjustment in plan version migrations. + /// The adjustment id this adjustment replaces. This adjustment will take the + /// place of the replaced adjustment in plan version migrations. /// public required string? ReplacesAdjustmentID { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } } /// @@ -182,27 +106,16 @@ public required string? ReplacesAdjustmentID /// public required double UsageDiscount { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } } + /// public override void Validate() { _ = this.ID; this.AdjustmentType.Validate(); - foreach (var item in this.AppliesToPriceIDs) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters) { item.Validate(); @@ -214,20 +127,281 @@ public override void Validate() _ = this.UsageDiscount; } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] public PlanPhaseUsageDiscountAdjustment() { } + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseUsageDiscountAdjustment( + PlanPhaseUsageDiscountAdjustment planPhaseUsageDiscountAdjustment + ) + : base(planPhaseUsageDiscountAdjustment) { } + + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + public PlanPhaseUsageDiscountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhaseUsageDiscountAdjustment(Generic::Dictionary properties) + [System::Obsolete("Required properties are deprecated: applies_to_price_ids")] + [SetsRequiredMembers] + PlanPhaseUsageDiscountAdjustment(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanPhaseUsageDiscountAdjustment FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseUsageDiscountAdjustmentFromRaw : IFromRawJson +{ + /// + public PlanPhaseUsageDiscountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseUsageDiscountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanPhaseUsageDiscountAdjustmentAdjustmentTypeConverter))] +public enum PlanPhaseUsageDiscountAdjustmentAdjustmentType +{ + UsageDiscount, +} + +sealed class PlanPhaseUsageDiscountAdjustmentAdjustmentTypeConverter + : JsonConverter +{ + public override PlanPhaseUsageDiscountAdjustmentAdjustmentType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_discount" => PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount, + _ => (PlanPhaseUsageDiscountAdjustmentAdjustmentType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseUsageDiscountAdjustmentAdjustmentType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseUsageDiscountAdjustmentAdjustmentType.UsageDiscount => "usage_discount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PlanPhaseUsageDiscountAdjustmentFilter, + PlanPhaseUsageDiscountAdjustmentFilterFromRaw + >) +)] +public sealed record class PlanPhaseUsageDiscountAdjustmentFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PlanPhaseUsageDiscountAdjustmentFilter() { } + + public PlanPhaseUsageDiscountAdjustmentFilter( + PlanPhaseUsageDiscountAdjustmentFilter planPhaseUsageDiscountAdjustmentFilter + ) + : base(planPhaseUsageDiscountAdjustmentFilter) { } + + public PlanPhaseUsageDiscountAdjustmentFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPhaseUsageDiscountAdjustmentFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPhaseUsageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPhaseUsageDiscountAdjustmentFilterFromRaw + : IFromRawJson +{ + /// + public PlanPhaseUsageDiscountAdjustmentFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanPhaseUsageDiscountAdjustmentFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PlanPhaseUsageDiscountAdjustmentFilterFieldConverter))] +public enum PlanPhaseUsageDiscountAdjustmentFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PlanPhaseUsageDiscountAdjustmentFilterFieldConverter + : JsonConverter +{ + public override PlanPhaseUsageDiscountAdjustmentFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PlanPhaseUsageDiscountAdjustmentFilterField.PriceID, + "item_id" => PlanPhaseUsageDiscountAdjustmentFilterField.ItemID, + "price_type" => PlanPhaseUsageDiscountAdjustmentFilterField.PriceType, + "currency" => PlanPhaseUsageDiscountAdjustmentFilterField.Currency, + "pricing_unit_id" => PlanPhaseUsageDiscountAdjustmentFilterField.PricingUnitID, + _ => (PlanPhaseUsageDiscountAdjustmentFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseUsageDiscountAdjustmentFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseUsageDiscountAdjustmentFilterField.PriceID => "price_id", + PlanPhaseUsageDiscountAdjustmentFilterField.ItemID => "item_id", + PlanPhaseUsageDiscountAdjustmentFilterField.PriceType => "price_type", + PlanPhaseUsageDiscountAdjustmentFilterField.Currency => "currency", + PlanPhaseUsageDiscountAdjustmentFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PlanPhaseUsageDiscountAdjustmentFilterOperatorConverter))] +public enum PlanPhaseUsageDiscountAdjustmentFilterOperator +{ + Includes, + Excludes, +} + +sealed class PlanPhaseUsageDiscountAdjustmentFilterOperatorConverter + : JsonConverter +{ + public override PlanPhaseUsageDiscountAdjustmentFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes, + "excludes" => PlanPhaseUsageDiscountAdjustmentFilterOperator.Excludes, + _ => (PlanPhaseUsageDiscountAdjustmentFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPhaseUsageDiscountAdjustmentFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + PlanPhaseUsageDiscountAdjustmentFilterOperator.Includes => "includes", + PlanPhaseUsageDiscountAdjustmentFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/PlanPhaseUsageDiscountAdjustmentProperties/AdjustmentType.cs b/src/Orb/Models/PlanPhaseUsageDiscountAdjustmentProperties/AdjustmentType.cs deleted file mode 100644 index 2b99063b..00000000 --- a/src/Orb/Models/PlanPhaseUsageDiscountAdjustmentProperties/AdjustmentType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PlanPhaseUsageDiscountAdjustmentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class AdjustmentType(string value) : Orb::IEnum -{ - public static readonly AdjustmentType UsageDiscount = new("usage_discount"); - - readonly string _value = value; - - public enum Value - { - UsageDiscount, - } - - public Value Known() => - _value switch - { - "usage_discount" => Value.UsageDiscount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static AdjustmentType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParams.cs b/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParams.cs index 0d309f60..5444eedf 100644 --- a/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParams.cs +++ b/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Plans.ExternalPlanID; @@ -10,37 +14,75 @@ namespace Orb.Models.Plans.ExternalPlanID; /// included in the plan and their configuration, as well as the product that the /// plan is attached to. /// -/// If multiple plans are found to contain the specified external_plan_id, the active -/// plans will take priority over archived ones, and among those, the endpoint will -/// return the most recently created plan. +/// If multiple plans are found to contain the specified external_plan_id, +/// the active plans will take priority over archived ones, and among those, the endpoint +/// will return the most recently created plan. /// -/// ## Serialized prices Orb supports a few different pricing models out of the box. -/// Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) +/// ## Serialized prices Orb supports a few different pricing models out of +/// the box. Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) /// object. The `model_type` field determines the key for the configuration object /// that is present. A detailed explanation of price types can be found in the [Price -/// schema](/core-concepts#plan-and-price). " +/// schema](/core-concepts#plan-and-price). " /// -public sealed record class ExternalPlanIDFetchParams : Orb::ParamsBase +public sealed record class ExternalPlanIDFetchParams : ParamsBase { - public required string ExternalPlanID; + public string? ExternalPlanID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public ExternalPlanIDFetchParams() { } + + public ExternalPlanIDFetchParams(ExternalPlanIDFetchParams externalPlanIDFetchParams) + : base(externalPlanIDFetchParams) { } + + public ExternalPlanIDFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPlanIDFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPlanIDFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/external_plan_id/{0}", this.ExternalPlanID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParams.cs b/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParams.cs index 9efafbb4..b7d7c007 100644 --- a/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParams.cs +++ b/src/Orb/Models/Plans/ExternalPlanID/ExternalPlanIDUpdateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Plans.ExternalPlanID; @@ -11,13 +13,17 @@ namespace Orb.Models.Plans.ExternalPlanID; /// This endpoint can be used to update the `external_plan_id`, and `metadata` of /// an existing plan. /// -/// Other fields on a plan are currently immutable. +/// Other fields on a plan are currently immutable. /// -public sealed record class ExternalPlanIDUpdateParams : Orb::ParamsBase +public sealed record class ExternalPlanIDUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string OtherExternalPlanID; + public string? OtherExternalPlanID { get; init; } /// /// An optional user-defined ID for this plan resource, used throughout the system @@ -26,19 +32,8 @@ public sealed record class ExternalPlanIDUpdateParams : Orb::ParamsBase /// public string? ExternalPlanID { - get - { - if (!this.BodyProperties.TryGetValue("external_plan_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_plan_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_plan_id"); } + init { JsonModel.Set(this._rawBodyData, "external_plan_id", value); } } /// @@ -46,44 +41,91 @@ public string? ExternalPlanID /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public ExternalPlanIDUpdateParams() { } + + public ExternalPlanIDUpdateParams(ExternalPlanIDUpdateParams externalPlanIDUpdateParams) + : base(externalPlanIDUpdateParams) + { + this._rawBodyData = [.. externalPlanIDUpdateParams._rawBodyData]; + } + + public ExternalPlanIDUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPlanIDUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPlanIDUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/external_plan_id/{0}", this.OtherExternalPlanID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Plans/Plan.cs b/src/Orb/Models/Plans/Plan.cs index 6942de5b..561a9829 100644 --- a/src/Orb/Models/Plans/Plan.cs +++ b/src/Orb/Models/Plans/Plan.cs @@ -1,10 +1,11 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using Models = Orb.Models; -using Orb = Orb; -using PlanProperties = Orb.Models.Plans.PlanProperties; -using Serialization = System.Text.Json.Serialization; using System = System; namespace Orb.Models.Plans; @@ -14,109 +15,64 @@ namespace Orb.Models.Plans; /// be subscribed to by a customer. Plans define the billing behavior of the subscription. /// You can see more about how to configure prices in the [Price resource](/reference/price). /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Plan : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Plan : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// /// Adjustments for this plan. If the plan has phases, this includes adjustments /// across all phases of the plan. /// - public required Generic::List Adjustments + public required IReadOnlyList Adjustments { - get - { - if (!this.Properties.TryGetValue("adjustments", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustments", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustments"); - } - set { this.Properties["adjustments"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "adjustments"); } + init { JsonModel.Set(this._rawData, "adjustments", value); } } - public required PlanProperties::BasePlan? BasePlan + /// + /// Legacy field representing the parent plan if the current plan is a 'child + /// plan', overriding prices from the parent. + /// + [System::Obsolete("deprecated")] + public required BasePlan? BasePlan { - get - { - if (!this.Properties.TryGetValue("base_plan", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "base_plan", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["base_plan"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "base_plan"); } + init { JsonModel.Set(this._rawData, "base_plan", value); } } /// - /// The parent plan id if the given plan was created by overriding one or more - /// of the parent's prices + /// Legacy field representing the parent plan ID if the current plan is a 'child + /// plan', overriding prices from the parent. /// + [System::Obsolete("deprecated")] public required string? BasePlanID { - get - { - if (!this.Properties.TryGetValue("base_plan_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "base_plan_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["base_plan_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "base_plan_id"); } + init { JsonModel.Set(this._rawData, "base_plan_id", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// /// An ISO 4217 currency string or custom pricing unit (`credits`) for this plan's prices. /// + [System::Obsolete("deprecated")] public required string Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// @@ -125,53 +81,21 @@ public required string Currency /// public required string? DefaultInvoiceMemo { - get - { - if (!this.Properties.TryGetValue("default_invoice_memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "default_invoice_memo", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawData, "default_invoice_memo", value); } } public required string Description { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("description"); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } } - public required Models::Discount? Discount + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } } /// @@ -181,20 +105,8 @@ public required string Description /// public required string? ExternalPlanID { - get - { - if (!this.Properties.TryGetValue("external_plan_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_plan_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_plan_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_plan_id"); } + init { JsonModel.Set(this._rawData, "external_plan_id", value); } } /// @@ -203,51 +115,22 @@ public required string? ExternalPlanID /// public required string InvoicingCurrency { - get - { - if (!this.Properties.TryGetValue("invoicing_currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoicing_currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("invoicing_currency"); - } - set - { - this.Properties["invoicing_currency"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawData, "invoicing_currency"); } + init { JsonModel.Set(this._rawData, "invoicing_currency", value); } } - public required Models::Maximum? Maximum + [System::Obsolete("deprecated")] + public required Maximum? Maximum { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } } + [System::Obsolete("deprecated")] public required string? MaximumAmount { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } } /// @@ -256,238 +139,1185 @@ public required string? MaximumAmount /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } } - public required Models::Minimum? Minimum + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Determines the difference between the invoice issue date and the due date. + /// A value of "0" here signifies that invoices are due on issue, whereas a value + /// of "30" means that the customer has a month to pay the invoice before its + /// overdue. Note that individual subscriptions or invoices may set a different + /// net terms configuration. + /// + public required long? NetTerms + { + get { return JsonModel.GetNullableStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } + } + + public required IReadOnlyList? PlanPhases + { + get { return JsonModel.GetNullableClass>(this.RawData, "plan_phases"); } + init { JsonModel.Set(this._rawData, "plan_phases", value); } + } + + /// + /// Prices for this plan. If the plan has phases, this includes prices across + /// all phases of the plan. + /// + public required IReadOnlyList Prices + { + get { return JsonModel.GetNotNullClass>(this.RawData, "prices"); } + init { JsonModel.Set(this._rawData, "prices", value); } + } + + public required Product Product + { + get { return JsonModel.GetNotNullClass(this.RawData, "product"); } + init { JsonModel.Set(this._rawData, "product", value); } + } + + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); + return JsonModel.GetNotNullClass>(this.RawData, "status"); + } + init { JsonModel.Set(this._rawData, "status", value); } + } + + public required TrialConfig TrialConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "trial_config"); } + init { JsonModel.Set(this._rawData, "trial_config", value); } + } + + public required long Version + { + get { return JsonModel.GetNotNullStruct(this.RawData, "version"); } + init { JsonModel.Set(this._rawData, "version", value); } + } - return Json::JsonSerializer.Deserialize(element); + /// + public override void Validate() + { + _ = this.ID; + foreach (var item in this.Adjustments) + { + item.Validate(); } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } + this.BasePlan?.Validate(); + _ = this.BasePlanID; + _ = this.CreatedAt; + _ = this.Currency; + _ = this.DefaultInvoiceMemo; + _ = this.Description; + this.Discount?.Validate(); + _ = this.ExternalPlanID; + _ = this.InvoicingCurrency; + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + _ = this.Name; + _ = this.NetTerms; + foreach (var item in this.PlanPhases ?? []) + { + item.Validate(); + } + foreach (var item in this.Prices) + { + item.Validate(); + } + this.Product.Validate(); + this.Status.Validate(); + this.TrialConfig.Validate(); + _ = this.Version; } - public required string? MinimumAmount + [System::Obsolete( + "Required properties are deprecated: base_plan, base_plan_id, currency, discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Plan() { } + + [System::Obsolete( + "Required properties are deprecated: base_plan, base_plan_id, currency, discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Plan(Plan plan) + : base(plan) { } + + [System::Obsolete( + "Required properties are deprecated: base_plan, base_plan_id, currency, discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Plan(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: base_plan, base_plan_id, currency, discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Plan(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Plan FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanFromRaw : IFromRawJson +{ + /// + public Plan FromRawUnchecked(IReadOnlyDictionary rawData) => + Plan.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanAdjustmentConverter))] +public record class PlanAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ID { get { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return Match( + planPhaseUsageDiscount: (x) => x.ID, + planPhaseAmountDiscount: (x) => x.ID, + planPhasePercentageDiscount: (x) => x.ID, + planPhaseMinimum: (x) => x.ID, + planPhaseMaximum: (x) => x.ID + ); } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } } - public required string Name + public bool IsInvoiceLevel { get { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); + return Match( + planPhaseUsageDiscount: (x) => x.IsInvoiceLevel, + planPhaseAmountDiscount: (x) => x.IsInvoiceLevel, + planPhasePercentageDiscount: (x) => x.IsInvoiceLevel, + planPhaseMinimum: (x) => x.IsInvoiceLevel, + planPhaseMaximum: (x) => x.IsInvoiceLevel + ); } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } } - /// - /// Determines the difference between the invoice issue date and the due date. A - /// value of "0" here signifies that invoices are due on issue, whereas a value - /// of "30" means that the customer has a month to pay the invoice before its overdue. - /// Note that individual subscriptions or invoices may set a different net terms configuration. - /// - public required long? NetTerms + public long? PlanPhaseOrder { get { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return Match( + planPhaseUsageDiscount: (x) => x.PlanPhaseOrder, + planPhaseAmountDiscount: (x) => x.PlanPhaseOrder, + planPhasePercentageDiscount: (x) => x.PlanPhaseOrder, + planPhaseMinimum: (x) => x.PlanPhaseOrder, + planPhaseMaximum: (x) => x.PlanPhaseOrder + ); } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } } - public required Generic::List? PlanPhases + public string? Reason { get { - if (!this.Properties.TryGetValue("plan_phases", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phases", - "Missing required argument" - ); + return Match( + planPhaseUsageDiscount: (x) => x.Reason, + planPhaseAmountDiscount: (x) => x.Reason, + planPhasePercentageDiscount: (x) => x.Reason, + planPhaseMinimum: (x) => x.Reason, + planPhaseMaximum: (x) => x.Reason + ); + } + } - return Json::JsonSerializer.Deserialize?>( - element + public string? ReplacesAdjustmentID + { + get + { + return Match( + planPhaseUsageDiscount: (x) => x.ReplacesAdjustmentID, + planPhaseAmountDiscount: (x) => x.ReplacesAdjustmentID, + planPhasePercentageDiscount: (x) => x.ReplacesAdjustmentID, + planPhaseMinimum: (x) => x.ReplacesAdjustmentID, + planPhaseMaximum: (x) => x.ReplacesAdjustmentID ); } - set { this.Properties["plan_phases"] = Json::JsonSerializer.SerializeToElement(value); } + } + + public PlanAdjustment( + Models::PlanPhaseUsageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanAdjustment( + Models::PlanPhaseAmountDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanAdjustment( + Models::PlanPhasePercentageDiscountAdjustment value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PlanAdjustment(Models::PlanPhaseMinimumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PlanAdjustment(Models::PlanPhaseMaximumAdjustment value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PlanAdjustment(JsonElement element) + { + this._element = element; } /// - /// Prices for this plan. If the plan has phases, this includes prices across all - /// phases of the plan. + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseUsageDiscount(out var value)) { + /// // `value` is of type `Models::PlanPhaseUsageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// /// - public required Generic::List Prices + public bool TryPickPlanPhaseUsageDiscount( + [NotNullWhen(true)] out Models::PlanPhaseUsageDiscountAdjustment? value + ) { - get - { - if (!this.Properties.TryGetValue("prices", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "prices", - "Missing required argument" - ); + value = this.Value as Models::PlanPhaseUsageDiscountAdjustment; + return value != null; + } - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("prices"); - } - set { this.Properties["prices"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseAmountDiscount(out var value)) { + /// // `value` is of type `Models::PlanPhaseAmountDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseAmountDiscount( + [NotNullWhen(true)] out Models::PlanPhaseAmountDiscountAdjustment? value + ) + { + value = this.Value as Models::PlanPhaseAmountDiscountAdjustment; + return value != null; } - public required PlanProperties::Product Product + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhasePercentageDiscount(out var value)) { + /// // `value` is of type `Models::PlanPhasePercentageDiscountAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhasePercentageDiscount( + [NotNullWhen(true)] out Models::PlanPhasePercentageDiscountAdjustment? value + ) { - get - { - if (!this.Properties.TryGetValue("product", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "product", - "Missing required argument" - ); + value = this.Value as Models::PlanPhasePercentageDiscountAdjustment; + return value != null; + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("product"); - } - set { this.Properties["product"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseMinimum(out var value)) { + /// // `value` is of type `Models::PlanPhaseMinimumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseMinimum( + [NotNullWhen(true)] out Models::PlanPhaseMinimumAdjustment? value + ) + { + value = this.Value as Models::PlanPhaseMinimumAdjustment; + return value != null; } - public required PlanProperties::Status Status + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPlanPhaseMaximum(out var value)) { + /// // `value` is of type `Models::PlanPhaseMaximumAdjustment` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPlanPhaseMaximum( + [NotNullWhen(true)] out Models::PlanPhaseMaximumAdjustment? value + ) { - get + value = this.Value as Models::PlanPhaseMaximumAdjustment; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (Models::PlanPhaseUsageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseAmountDiscountAdjustment value) => {...}, + /// (Models::PlanPhasePercentageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseMinimumAdjustment value) => {...}, + /// (Models::PlanPhaseMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action planPhaseUsageDiscount, + System::Action planPhaseAmountDiscount, + System::Action planPhasePercentageDiscount, + System::Action planPhaseMinimum, + System::Action planPhaseMaximum + ) + { + switch (this.Value) { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" + case Models::PlanPhaseUsageDiscountAdjustment value: + planPhaseUsageDiscount(value); + break; + case Models::PlanPhaseAmountDiscountAdjustment value: + planPhaseAmountDiscount(value); + break; + case Models::PlanPhasePercentageDiscountAdjustment value: + planPhasePercentageDiscount(value); + break; + case Models::PlanPhaseMinimumAdjustment value: + planPhaseMinimum(value); + break; + case Models::PlanPhaseMaximumAdjustment value: + planPhaseMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PlanAdjustment" ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } } - public required PlanProperties::TrialConfig TrialConfig + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (Models::PlanPhaseUsageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseAmountDiscountAdjustment value) => {...}, + /// (Models::PlanPhasePercentageDiscountAdjustment value) => {...}, + /// (Models::PlanPhaseMinimumAdjustment value) => {...}, + /// (Models::PlanPhaseMaximumAdjustment value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func planPhaseUsageDiscount, + System::Func planPhaseAmountDiscount, + System::Func planPhasePercentageDiscount, + System::Func planPhaseMinimum, + System::Func planPhaseMaximum + ) { - get + return this.Value switch { - if (!this.Properties.TryGetValue("trial_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "trial_config", - "Missing required argument" - ); + Models::PlanPhaseUsageDiscountAdjustment value => planPhaseUsageDiscount(value), + Models::PlanPhaseAmountDiscountAdjustment value => planPhaseAmountDiscount(value), + Models::PlanPhasePercentageDiscountAdjustment value => planPhasePercentageDiscount( + value + ), + Models::PlanPhaseMinimumAdjustment value => planPhaseMinimum(value), + Models::PlanPhaseMaximumAdjustment value => planPhaseMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PlanAdjustment" + ), + }; + } + + public static implicit operator PlanAdjustment( + Models::PlanPhaseUsageDiscountAdjustment value + ) => new(value); + + public static implicit operator PlanAdjustment( + Models::PlanPhaseAmountDiscountAdjustment value + ) => new(value); + + public static implicit operator PlanAdjustment( + Models::PlanPhasePercentageDiscountAdjustment value + ) => new(value); - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("trial_config"); + public static implicit operator PlanAdjustment(Models::PlanPhaseMinimumAdjustment value) => + new(value); + + public static implicit operator PlanAdjustment(Models::PlanPhaseMaximumAdjustment value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of PlanAdjustment"); } - set { this.Properties["trial_config"] = Json::JsonSerializer.SerializeToElement(value); } + this.Switch( + (planPhaseUsageDiscount) => planPhaseUsageDiscount.Validate(), + (planPhaseAmountDiscount) => planPhaseAmountDiscount.Validate(), + (planPhasePercentageDiscount) => planPhasePercentageDiscount.Validate(), + (planPhaseMinimum) => planPhaseMinimum.Validate(), + (planPhaseMaximum) => planPhaseMaximum.Validate() + ); } - public required long Version + public virtual bool Equals(PlanAdjustment? other) { - get + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PlanAdjustmentConverter : JsonConverter +{ + public override PlanAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try { - if (!this.Properties.TryGetValue("version", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "version", - "Missing required argument" - ); + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "usage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } - return Json::JsonSerializer.Deserialize(element); + return new(element); + } + case "percentage_discount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PlanAdjustment(element); + } } - set { this.Properties["version"] = Json::JsonSerializer.SerializeToElement(value); } } + public override void Write( + Utf8JsonWriter writer, + PlanAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Legacy field representing the parent plan if the current plan is a 'child plan', +/// overriding prices from the parent. +/// +[System::Obsolete("deprecated")] +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BasePlan : JsonModel +{ + public required string? ID + { + get { return JsonModel.GetNullableClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// An optional user-defined ID for this plan resource, used throughout the system + /// as an alias for this Plan. Use this field to identify a plan by an existing + /// identifier in your system. + /// + public required string? ExternalPlanID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_plan_id"); } + init { JsonModel.Set(this._rawData, "external_plan_id", value); } + } + + public required string? Name + { + get { return JsonModel.GetNullableClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// public override void Validate() { _ = this.ID; - foreach (var item in this.Adjustments) + _ = this.ExternalPlanID; + _ = this.Name; + } + + public BasePlan() { } + + public BasePlan(BasePlan basePlan) + : base(basePlan) { } + + public BasePlan(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BasePlan(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BasePlan FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BasePlanFromRaw : IFromRawJson +{ + /// + public BasePlan FromRawUnchecked(IReadOnlyDictionary rawData) => + BasePlan.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PlanPlanPhase : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string? Description + { + get { return JsonModel.GetNullableClass(this.RawData, "description"); } + init { JsonModel.Set(this._rawData, "description", value); } + } + + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + /// + /// How many terms of length `duration_unit` this phase is active for. If null, + /// this phase is evergreen and active indefinitely + /// + public required long? Duration + { + get { return JsonModel.GetNullableStruct(this.RawData, "duration"); } + init { JsonModel.Set(this._rawData, "duration", value); } + } + + public required ApiEnum? DurationUnit + { + get { - item.Validate(); + return JsonModel.GetNullableClass>( + this.RawData, + "duration_unit" + ); } - this.BasePlan?.Validate(); - _ = this.BasePlanID; - _ = this.CreatedAt; - _ = this.Currency; - _ = this.DefaultInvoiceMemo; + init { JsonModel.Set(this._rawData, "duration_unit", value); } + } + + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Determines the ordering of the phase in a plan's lifecycle. 1 = first phase. + /// + public required long Order + { + get { return JsonModel.GetNotNullStruct(this.RawData, "order"); } + init { JsonModel.Set(this._rawData, "order", value); } + } + + /// + public override void Validate() + { + _ = this.ID; _ = this.Description; this.Discount?.Validate(); - _ = this.ExternalPlanID; - _ = this.InvoicingCurrency; + _ = this.Duration; + this.DurationUnit?.Validate(); this.Maximum?.Validate(); _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } this.Minimum?.Validate(); _ = this.MinimumAmount; _ = this.Name; - _ = this.NetTerms; - foreach (var item in this.PlanPhases ?? []) + _ = this.Order; + } + + public PlanPlanPhase() { } + + public PlanPlanPhase(PlanPlanPhase planPlanPhase) + : base(planPlanPhase) { } + + public PlanPlanPhase(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPlanPhase(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPlanPhase FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanPlanPhaseFromRaw : IFromRawJson +{ + /// + public PlanPlanPhase FromRawUnchecked(IReadOnlyDictionary rawData) => + PlanPlanPhase.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanPlanPhaseDurationUnitConverter))] +public enum PlanPlanPhaseDurationUnit +{ + Daily, + Monthly, + Quarterly, + SemiAnnual, + Annual, +} + +sealed class PlanPlanPhaseDurationUnitConverter : JsonConverter +{ + public override PlanPlanPhaseDurationUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - item.Validate(); + "daily" => PlanPlanPhaseDurationUnit.Daily, + "monthly" => PlanPlanPhaseDurationUnit.Monthly, + "quarterly" => PlanPlanPhaseDurationUnit.Quarterly, + "semi_annual" => PlanPlanPhaseDurationUnit.SemiAnnual, + "annual" => PlanPlanPhaseDurationUnit.Annual, + _ => (PlanPlanPhaseDurationUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanPlanPhaseDurationUnit value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanPlanPhaseDurationUnit.Daily => "daily", + PlanPlanPhaseDurationUnit.Monthly => "monthly", + PlanPlanPhaseDurationUnit.Quarterly => "quarterly", + PlanPlanPhaseDurationUnit.SemiAnnual => "semi_annual", + PlanPlanPhaseDurationUnit.Annual => "annual", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Product : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - foreach (var item in this.Prices) + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CreatedAt; + _ = this.Name; + } + + public Product() { } + + public Product(Product product) + : base(product) { } + + public Product(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Product(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Product FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ProductFromRaw : IFromRawJson +{ + /// + public Product FromRawUnchecked(IReadOnlyDictionary rawData) => + Product.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PlanStatusConverter))] +public enum PlanStatus +{ + Active, + Archived, + Draft, +} + +sealed class PlanStatusConverter : JsonConverter +{ + public override PlanStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - item.Validate(); + "active" => PlanStatus.Active, + "archived" => PlanStatus.Archived, + "draft" => PlanStatus.Draft, + _ => (PlanStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanStatus.Active => "active", + PlanStatus.Archived => "archived", + PlanStatus.Draft => "draft", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TrialConfig : JsonModel +{ + public required long? TrialPeriod + { + get { return JsonModel.GetNullableStruct(this.RawData, "trial_period"); } + init { JsonModel.Set(this._rawData, "trial_period", value); } + } + + public required ApiEnum TrialPeriodUnit + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "trial_period_unit" + ); } - this.Product.Validate(); - this.Status.Validate(); - this.TrialConfig.Validate(); - _ = this.Version; + init { JsonModel.Set(this._rawData, "trial_period_unit", value); } } - public Plan() { } + /// + public override void Validate() + { + _ = this.TrialPeriod; + this.TrialPeriodUnit.Validate(); + } + + public TrialConfig() { } + + public TrialConfig(TrialConfig trialConfig) + : base(trialConfig) { } + + public TrialConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Plan(Generic::Dictionary properties) + [SetsRequiredMembers] + TrialConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Plan FromRawUnchecked(Generic::Dictionary properties) + /// + public static TrialConfig FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TrialConfigFromRaw : IFromRawJson +{ + /// + public TrialConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + TrialConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TrialPeriodUnitConverter))] +public enum TrialPeriodUnit +{ + Days, +} + +sealed class TrialPeriodUnitConverter : JsonConverter +{ + public override TrialPeriodUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "days" => TrialPeriodUnit.Days, + _ => (TrialPeriodUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TrialPeriodUnit value, + JsonSerializerOptions options + ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + TrialPeriodUnit.Days => "days", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Plans/PlanCreateParams.cs b/src/Orb/Models/Plans/PlanCreateParams.cs index e275b301..98e88418 100644 --- a/src/Orb/Models/Plans/PlanCreateParams.cs +++ b/src/Orb/Models/Plans/PlanCreateParams.cs @@ -1,89 +1,72 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using PlanCreateParamsProperties = Orb.Models.Plans.PlanCreateParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Plans; /// /// This endpoint allows creation of plans including their prices. /// -public sealed record class PlanCreateParams : Orb::ParamsBase +public sealed record class PlanCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// An ISO 4217 currency string for invoices generated by subscriptions on this plan. /// public required string Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } public required string Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } } /// - /// Prices for this plan. If the plan has phases, this includes prices across all - /// phases of the plan. + /// Prices for this plan. If the plan has phases, this includes prices across + /// all phases of the plan. /// - public required Generic::List Prices + public required IReadOnlyList Prices { get { - if (!this.BodyProperties.TryGetValue("prices", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "prices", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("prices"); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "prices" + ); } - set { this.BodyProperties["prices"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "prices", value); } } /// /// Adjustments for this plan. If the plan has phases, this includes adjustments /// across all phases of the plan. /// - public Generic::List? Adjustments + public IReadOnlyList? Adjustments { get { - if (!this.BodyProperties.TryGetValue("adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "adjustments" ); } - set { this.BodyProperties["adjustments"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "adjustments", value); } } /// @@ -91,134 +74,8130 @@ public required string Name /// public string? DefaultInvoiceMemo { - get - { - if ( - !this.BodyProperties.TryGetValue( - "default_invoice_memo", - out Json::JsonElement element - ) - ) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawBodyData, "default_invoice_memo", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set + public string? ExternalPlanID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_plan_id"); } + init { JsonModel.Set(this._rawBodyData, "external_plan_id", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get { - this.BodyProperties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" ); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } - public string? ExternalPlanID + /// + /// The net terms determines the difference between the invoice date and the + /// issue date for the invoice. If you intend the invoice to be due on issue, + /// set this to 0. + /// + public long? NetTerms + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "net_terms"); } + init { JsonModel.Set(this._rawBodyData, "net_terms", value); } + } + + /// + /// Configuration of pre-defined phases, each with their own prices and adjustments. + /// Leave unspecified for plans with a single phase. + /// + public IReadOnlyList? PlanPhases + { + get { return JsonModel.GetNullableClass>(this.RawBodyData, "plan_phases"); } + init { JsonModel.Set(this._rawBodyData, "plan_phases", value); } + } + + /// + /// The status of the plan to create (either active or draft). If not specified, + /// this defaults to active. + /// + public ApiEnum? Status { get { - if (!this.BodyProperties.TryGetValue("external_plan_id", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableClass>( + this.RawBodyData, + "status" + ); + } + init + { + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawBodyData, "status", value); } - set + } + + public PlanCreateParams() { } + + public PlanCreateParams(PlanCreateParams planCreateParams) + : base(planCreateParams) + { + this._rawBodyData = [.. planCreateParams._rawBodyData]; + } + + public PlanCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PlanCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/plans") { - this.BodyProperties["external_plan_id"] = Json::JsonSerializer.SerializeToElement( - value - ); + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } +} +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Price : JsonModel +{ /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. + /// The allocation price to add to the plan. /// - public Generic::Dictionary? Metadata + public NewAllocationPrice? AllocationPrice { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "allocation_price", value); } } /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. + /// The phase to add this price to. /// - public long? NetTerms + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New plan price request body params. + /// + public PricePrice? PriceValue + { + get { return JsonModel.GetNullableClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + public override void Validate() + { + this.AllocationPrice?.Validate(); + _ = this.PlanPhaseOrder; + this.PriceValue?.Validate(); + } + + public Price() { } + + public Price(global::Orb.Models.Plans.Price price) + : base(price) { } + + public Price(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Price(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.Price FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.Price FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.Price.FromRawUnchecked(rawData); +} + +/// +/// New plan price request body params. +/// +[JsonConverter(typeof(PricePriceConverter))] +public record class PricePrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newPlanUnit: (x) => x.ItemID, + newPlanTiered: (x) => x.ItemID, + newPlanBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newPlanPackage: (x) => x.ItemID, + newPlanMatrix: (x) => x.ItemID, + newPlanThresholdTotalAmount: (x) => x.ItemID, + newPlanTieredPackage: (x) => x.ItemID, + newPlanTieredWithMinimum: (x) => x.ItemID, + newPlanGroupedTiered: (x) => x.ItemID, + newPlanTieredPackageWithMinimum: (x) => x.ItemID, + newPlanPackageWithAllocation: (x) => x.ItemID, + newPlanUnitWithPercent: (x) => x.ItemID, + newPlanMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newPlanUnitWithProration: (x) => x.ItemID, + newPlanGroupedAllocation: (x) => x.ItemID, + newPlanBulkWithProration: (x) => x.ItemID, + newPlanGroupedWithProratedMinimum: (x) => x.ItemID, + newPlanGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newPlanMatrixWithDisplayName: (x) => x.ItemID, + newPlanGroupedTieredPackage: (x) => x.ItemID, + newPlanMaxGroupTieredPackage: (x) => x.ItemID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ItemID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ItemID, + newPlanCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newPlanMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name { get { - if (!this.BodyProperties.TryGetValue("net_terms", out Json::JsonElement element)) - return null; + return Match( + newPlanUnit: (x) => x.Name, + newPlanTiered: (x) => x.Name, + newPlanBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newPlanPackage: (x) => x.Name, + newPlanMatrix: (x) => x.Name, + newPlanThresholdTotalAmount: (x) => x.Name, + newPlanTieredPackage: (x) => x.Name, + newPlanTieredWithMinimum: (x) => x.Name, + newPlanGroupedTiered: (x) => x.Name, + newPlanTieredPackageWithMinimum: (x) => x.Name, + newPlanPackageWithAllocation: (x) => x.Name, + newPlanUnitWithPercent: (x) => x.Name, + newPlanMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newPlanUnitWithProration: (x) => x.Name, + newPlanGroupedAllocation: (x) => x.Name, + newPlanBulkWithProration: (x) => x.Name, + newPlanGroupedWithProratedMinimum: (x) => x.Name, + newPlanGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newPlanMatrixWithDisplayName: (x) => x.Name, + newPlanGroupedTieredPackage: (x) => x.Name, + newPlanMaxGroupTieredPackage: (x) => x.Name, + newPlanScalableMatrixWithUnitPricing: (x) => x.Name, + newPlanScalableMatrixWithTieredPricing: (x) => x.Name, + newPlanCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newPlanMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } - return Json::JsonSerializer.Deserialize(element); + public string? BillableMetricID + { + get + { + return Match( + newPlanUnit: (x) => x.BillableMetricID, + newPlanTiered: (x) => x.BillableMetricID, + newPlanBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newPlanPackage: (x) => x.BillableMetricID, + newPlanMatrix: (x) => x.BillableMetricID, + newPlanThresholdTotalAmount: (x) => x.BillableMetricID, + newPlanTieredPackage: (x) => x.BillableMetricID, + newPlanTieredWithMinimum: (x) => x.BillableMetricID, + newPlanGroupedTiered: (x) => x.BillableMetricID, + newPlanTieredPackageWithMinimum: (x) => x.BillableMetricID, + newPlanPackageWithAllocation: (x) => x.BillableMetricID, + newPlanUnitWithPercent: (x) => x.BillableMetricID, + newPlanMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newPlanUnitWithProration: (x) => x.BillableMetricID, + newPlanGroupedAllocation: (x) => x.BillableMetricID, + newPlanBulkWithProration: (x) => x.BillableMetricID, + newPlanGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newPlanGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newPlanMatrixWithDisplayName: (x) => x.BillableMetricID, + newPlanGroupedTieredPackage: (x) => x.BillableMetricID, + newPlanMaxGroupTieredPackage: (x) => x.BillableMetricID, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newPlanCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newPlanMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); } - set { this.BodyProperties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } } - /// - /// Configuration of pre-defined phases, each with their own prices and adjustments. - /// Leave unspecified for plans with a single phase. - /// - public Generic::List? PlanPhases + public bool? BilledInAdvance + { + get + { + return Match( + newPlanUnit: (x) => x.BilledInAdvance, + newPlanTiered: (x) => x.BilledInAdvance, + newPlanBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newPlanPackage: (x) => x.BilledInAdvance, + newPlanMatrix: (x) => x.BilledInAdvance, + newPlanThresholdTotalAmount: (x) => x.BilledInAdvance, + newPlanTieredPackage: (x) => x.BilledInAdvance, + newPlanTieredWithMinimum: (x) => x.BilledInAdvance, + newPlanGroupedTiered: (x) => x.BilledInAdvance, + newPlanTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newPlanPackageWithAllocation: (x) => x.BilledInAdvance, + newPlanUnitWithPercent: (x) => x.BilledInAdvance, + newPlanMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newPlanUnitWithProration: (x) => x.BilledInAdvance, + newPlanGroupedAllocation: (x) => x.BilledInAdvance, + newPlanBulkWithProration: (x) => x.BilledInAdvance, + newPlanGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newPlanGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newPlanMatrixWithDisplayName: (x) => x.BilledInAdvance, + newPlanGroupedTieredPackage: (x) => x.BilledInAdvance, + newPlanMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newPlanScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newPlanCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newPlanMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if (!this.BodyProperties.TryGetValue("plan_phases", out Json::JsonElement element)) - return null; + return Match( + newPlanUnit: (x) => x.BillingCycleConfiguration, + newPlanTiered: (x) => x.BillingCycleConfiguration, + newPlanBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newPlanPackage: (x) => x.BillingCycleConfiguration, + newPlanMatrix: (x) => x.BillingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newPlanTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedTiered: (x) => x.BillingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newPlanUnitWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanBulkWithProration: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newPlanMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } - return Json::JsonSerializer.Deserialize?>( - element + public double? ConversionRate + { + get + { + return Match( + newPlanUnit: (x) => x.ConversionRate, + newPlanTiered: (x) => x.ConversionRate, + newPlanBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newPlanPackage: (x) => x.ConversionRate, + newPlanMatrix: (x) => x.ConversionRate, + newPlanThresholdTotalAmount: (x) => x.ConversionRate, + newPlanTieredPackage: (x) => x.ConversionRate, + newPlanTieredWithMinimum: (x) => x.ConversionRate, + newPlanGroupedTiered: (x) => x.ConversionRate, + newPlanTieredPackageWithMinimum: (x) => x.ConversionRate, + newPlanPackageWithAllocation: (x) => x.ConversionRate, + newPlanUnitWithPercent: (x) => x.ConversionRate, + newPlanMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newPlanUnitWithProration: (x) => x.ConversionRate, + newPlanGroupedAllocation: (x) => x.ConversionRate, + newPlanBulkWithProration: (x) => x.ConversionRate, + newPlanGroupedWithProratedMinimum: (x) => x.ConversionRate, + newPlanGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newPlanMatrixWithDisplayName: (x) => x.ConversionRate, + newPlanGroupedTieredPackage: (x) => x.ConversionRate, + newPlanMaxGroupTieredPackage: (x) => x.ConversionRate, + newPlanScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newPlanScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newPlanCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newPlanMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate ); } - set { this.BodyProperties["plan_phases"] = Json::JsonSerializer.SerializeToElement(value); } } - /// - /// The status of the plan to create (either active or draft). If not specified, - /// this defaults to active. - /// - public PlanCreateParamsProperties::Status? Status + public string? Currency + { + get + { + return Match( + newPlanUnit: (x) => x.Currency, + newPlanTiered: (x) => x.Currency, + newPlanBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newPlanPackage: (x) => x.Currency, + newPlanMatrix: (x) => x.Currency, + newPlanThresholdTotalAmount: (x) => x.Currency, + newPlanTieredPackage: (x) => x.Currency, + newPlanTieredWithMinimum: (x) => x.Currency, + newPlanGroupedTiered: (x) => x.Currency, + newPlanTieredPackageWithMinimum: (x) => x.Currency, + newPlanPackageWithAllocation: (x) => x.Currency, + newPlanUnitWithPercent: (x) => x.Currency, + newPlanMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newPlanUnitWithProration: (x) => x.Currency, + newPlanGroupedAllocation: (x) => x.Currency, + newPlanBulkWithProration: (x) => x.Currency, + newPlanGroupedWithProratedMinimum: (x) => x.Currency, + newPlanGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newPlanMatrixWithDisplayName: (x) => x.Currency, + newPlanGroupedTieredPackage: (x) => x.Currency, + newPlanMaxGroupTieredPackage: (x) => x.Currency, + newPlanScalableMatrixWithUnitPricing: (x) => x.Currency, + newPlanScalableMatrixWithTieredPricing: (x) => x.Currency, + newPlanCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newPlanMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if (!this.BodyProperties.TryGetValue("status", out Json::JsonElement element)) - return null; + return Match( + newPlanUnit: (x) => x.DimensionalPriceConfiguration, + newPlanTiered: (x) => x.DimensionalPriceConfiguration, + newPlanBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newPlanPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMatrix: (x) => x.DimensionalPriceConfiguration, + newPlanThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newPlanMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newPlanGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newPlanMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } - return Json::JsonSerializer.Deserialize(element); + public string? ExternalPriceID + { + get + { + return Match( + newPlanUnit: (x) => x.ExternalPriceID, + newPlanTiered: (x) => x.ExternalPriceID, + newPlanBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newPlanPackage: (x) => x.ExternalPriceID, + newPlanMatrix: (x) => x.ExternalPriceID, + newPlanThresholdTotalAmount: (x) => x.ExternalPriceID, + newPlanTieredPackage: (x) => x.ExternalPriceID, + newPlanTieredWithMinimum: (x) => x.ExternalPriceID, + newPlanGroupedTiered: (x) => x.ExternalPriceID, + newPlanTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newPlanPackageWithAllocation: (x) => x.ExternalPriceID, + newPlanUnitWithPercent: (x) => x.ExternalPriceID, + newPlanMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newPlanUnitWithProration: (x) => x.ExternalPriceID, + newPlanGroupedAllocation: (x) => x.ExternalPriceID, + newPlanBulkWithProration: (x) => x.ExternalPriceID, + newPlanGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newPlanMatrixWithDisplayName: (x) => x.ExternalPriceID, + newPlanGroupedTieredPackage: (x) => x.ExternalPriceID, + newPlanMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newPlanCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newPlanMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); } - set { this.BodyProperties["status"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public double? FixedPriceQuantity { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/plans") + get { - Query = this.QueryString(client), - }.Uri; + return Match( + newPlanUnit: (x) => x.FixedPriceQuantity, + newPlanTiered: (x) => x.FixedPriceQuantity, + newPlanBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newPlanPackage: (x) => x.FixedPriceQuantity, + newPlanMatrix: (x) => x.FixedPriceQuantity, + newPlanThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newPlanTieredPackage: (x) => x.FixedPriceQuantity, + newPlanTieredWithMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedTiered: (x) => x.FixedPriceQuantity, + newPlanTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newPlanPackageWithAllocation: (x) => x.FixedPriceQuantity, + newPlanUnitWithPercent: (x) => x.FixedPriceQuantity, + newPlanMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newPlanUnitWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanBulkWithProration: (x) => x.FixedPriceQuantity, + newPlanGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newPlanGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newPlanMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newPlanGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newPlanMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newPlanScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newPlanCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newPlanMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } } - public Http::StringContent BodyContent() + public string? InvoiceGroupingKey { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + get + { + return Match( + newPlanUnit: (x) => x.InvoiceGroupingKey, + newPlanTiered: (x) => x.InvoiceGroupingKey, + newPlanBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newPlanPackage: (x) => x.InvoiceGroupingKey, + newPlanMatrix: (x) => x.InvoiceGroupingKey, + newPlanThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newPlanTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedTiered: (x) => x.InvoiceGroupingKey, + newPlanTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newPlanPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newPlanUnitWithPercent: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newPlanUnitWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanBulkWithProration: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newPlanMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newPlanGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newPlanCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newPlanMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newPlanUnit: (x) => x.InvoicingCycleConfiguration, + newPlanTiered: (x) => x.InvoicingCycleConfiguration, + newPlanBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newPlanPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMatrix: (x) => x.InvoicingCycleConfiguration, + newPlanThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newPlanTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newPlanMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newPlanGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newPlanScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newPlanCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newPlanMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public string? ReferenceID { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + newPlanUnit: (x) => x.ReferenceID, + newPlanTiered: (x) => x.ReferenceID, + newPlanBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newPlanPackage: (x) => x.ReferenceID, + newPlanMatrix: (x) => x.ReferenceID, + newPlanThresholdTotalAmount: (x) => x.ReferenceID, + newPlanTieredPackage: (x) => x.ReferenceID, + newPlanTieredWithMinimum: (x) => x.ReferenceID, + newPlanGroupedTiered: (x) => x.ReferenceID, + newPlanTieredPackageWithMinimum: (x) => x.ReferenceID, + newPlanPackageWithAllocation: (x) => x.ReferenceID, + newPlanUnitWithPercent: (x) => x.ReferenceID, + newPlanMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newPlanUnitWithProration: (x) => x.ReferenceID, + newPlanGroupedAllocation: (x) => x.ReferenceID, + newPlanBulkWithProration: (x) => x.ReferenceID, + newPlanGroupedWithProratedMinimum: (x) => x.ReferenceID, + newPlanGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newPlanMatrixWithDisplayName: (x) => x.ReferenceID, + newPlanGroupedTieredPackage: (x) => x.ReferenceID, + newPlanMaxGroupTieredPackage: (x) => x.ReferenceID, + newPlanScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newPlanScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newPlanCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newPlanMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); } } + + public PricePrice(NewPlanUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(global::Orb.Models.Plans.BulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice( + global::Orb.Models.Plans.TieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice( + global::Orb.Models.Plans.GroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanScalableMatrixWithUnitPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice( + NewPlanScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice( + global::Orb.Models.Plans.CumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PricePrice(NewPlanMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(global::Orb.Models.Plans.Percent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(global::Orb.Models.Plans.EventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PricePrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnit(out var value)) { + /// // `value` is of type `NewPlanUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnit([NotNullWhen(true)] out NewPlanUnitPrice? value) + { + value = this.Value as NewPlanUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTiered(out var value)) { + /// // `value` is of type `NewPlanTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTiered([NotNullWhen(true)] out NewPlanTieredPrice? value) + { + value = this.Value as NewPlanTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulk(out var value)) { + /// // `value` is of type `NewPlanBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulk([NotNullWhen(true)] out NewPlanBulkPrice? value) + { + value = this.Value as NewPlanBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `global::Orb.Models.Plans.BulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out global::Orb.Models.Plans.BulkWithFilters? value + ) + { + value = this.Value as global::Orb.Models.Plans.BulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackage(out var value)) { + /// // `value` is of type `NewPlanPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackage([NotNullWhen(true)] out NewPlanPackagePrice? value) + { + value = this.Value as NewPlanPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrix(out var value)) { + /// // `value` is of type `NewPlanMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrix([NotNullWhen(true)] out NewPlanMatrixPrice? value) + { + value = this.Value as NewPlanMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewPlanThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanThresholdTotalAmount( + [NotNullWhen(true)] out NewPlanThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewPlanThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackage(out var value)) { + /// // `value` is of type `NewPlanTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackage( + [NotNullWhen(true)] out NewPlanTieredPackagePrice? value + ) + { + value = this.Value as NewPlanTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredWithMinimum( + [NotNullWhen(true)] out NewPlanTieredWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTiered(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTiered( + [NotNullWhen(true)] out NewPlanGroupedTieredPrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewPlanTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanTieredPackageWithMinimum( + [NotNullWhen(true)] out NewPlanTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewPlanTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanPackageWithAllocation(out var value)) { + /// // `value` is of type `NewPlanPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanPackageWithAllocation( + [NotNullWhen(true)] out NewPlanPackageWithAllocationPrice? value + ) + { + value = this.Value as NewPlanPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithPercent(out var value)) { + /// // `value` is of type `NewPlanUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithPercent( + [NotNullWhen(true)] out NewPlanUnitWithPercentPrice? value + ) + { + value = this.Value as NewPlanUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewPlanMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithAllocation( + [NotNullWhen(true)] out NewPlanMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewPlanMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `global::Orb.Models.Plans.TieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] out global::Orb.Models.Plans.TieredWithProration? value + ) + { + value = this.Value as global::Orb.Models.Plans.TieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanUnitWithProration(out var value)) { + /// // `value` is of type `NewPlanUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanUnitWithProration( + [NotNullWhen(true)] out NewPlanUnitWithProrationPrice? value + ) + { + value = this.Value as NewPlanUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedAllocation(out var value)) { + /// // `value` is of type `NewPlanGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedAllocation( + [NotNullWhen(true)] out NewPlanGroupedAllocationPrice? value + ) + { + value = this.Value as NewPlanGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanBulkWithProration(out var value)) { + /// // `value` is of type `NewPlanBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanBulkWithProration( + [NotNullWhen(true)] out NewPlanBulkWithProrationPrice? value + ) + { + value = this.Value as NewPlanBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewPlanGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewPlanGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewPlanGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `global::Orb.Models.Plans.GroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out global::Orb.Models.Plans.GroupedWithMinMaxThresholds? value + ) + { + value = this.Value as global::Orb.Models.Plans.GroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewPlanMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMatrixWithDisplayName( + [NotNullWhen(true)] out NewPlanMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewPlanMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewPlanGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanGroupedTieredPackage( + [NotNullWhen(true)] out NewPlanGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewPlanGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewPlanMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMaxGroupTieredPackage( + [NotNullWhen(true)] out NewPlanMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewPlanMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewPlanScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewPlanScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewPlanScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewPlanCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanCumulativeGroupedBulk( + [NotNullWhen(true)] out NewPlanCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewPlanCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `global::Orb.Models.Plans.CumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out global::Orb.Models.Plans.CumulativeGroupedAllocation? value + ) + { + value = this.Value as global::Orb.Models.Plans.CumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPlanMinimumComposite(out var value)) { + /// // `value` is of type `NewPlanMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPlanMinimumComposite( + [NotNullWhen(true)] out NewPlanMinimumCompositePrice? value + ) + { + value = this.Value as NewPlanMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `global::Orb.Models.Plans.Percent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out global::Orb.Models.Plans.Percent? value) + { + value = this.Value as global::Orb.Models.Plans.Percent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `global::Orb.Models.Plans.EventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] out global::Orb.Models.Plans.EventOutput? value + ) + { + value = this.Value as global::Orb.Models.Plans.EventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Plans.BulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Plans.TieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Plans.GroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Plans.CumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Plans.Percent value) => {...}, + /// (global::Orb.Models.Plans.EventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPlanUnit, + System::Action newPlanTiered, + System::Action newPlanBulk, + System::Action bulkWithFilters, + System::Action newPlanPackage, + System::Action newPlanMatrix, + System::Action newPlanThresholdTotalAmount, + System::Action newPlanTieredPackage, + System::Action newPlanTieredWithMinimum, + System::Action newPlanGroupedTiered, + System::Action newPlanTieredPackageWithMinimum, + System::Action newPlanPackageWithAllocation, + System::Action newPlanUnitWithPercent, + System::Action newPlanMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newPlanUnitWithProration, + System::Action newPlanGroupedAllocation, + System::Action newPlanBulkWithProration, + System::Action newPlanGroupedWithProratedMinimum, + System::Action newPlanGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newPlanMatrixWithDisplayName, + System::Action newPlanGroupedTieredPackage, + System::Action newPlanMaxGroupTieredPackage, + System::Action newPlanScalableMatrixWithUnitPricing, + System::Action newPlanScalableMatrixWithTieredPricing, + System::Action newPlanCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newPlanMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewPlanUnitPrice value: + newPlanUnit(value); + break; + case NewPlanTieredPrice value: + newPlanTiered(value); + break; + case NewPlanBulkPrice value: + newPlanBulk(value); + break; + case global::Orb.Models.Plans.BulkWithFilters value: + bulkWithFilters(value); + break; + case NewPlanPackagePrice value: + newPlanPackage(value); + break; + case NewPlanMatrixPrice value: + newPlanMatrix(value); + break; + case NewPlanThresholdTotalAmountPrice value: + newPlanThresholdTotalAmount(value); + break; + case NewPlanTieredPackagePrice value: + newPlanTieredPackage(value); + break; + case NewPlanTieredWithMinimumPrice value: + newPlanTieredWithMinimum(value); + break; + case NewPlanGroupedTieredPrice value: + newPlanGroupedTiered(value); + break; + case NewPlanTieredPackageWithMinimumPrice value: + newPlanTieredPackageWithMinimum(value); + break; + case NewPlanPackageWithAllocationPrice value: + newPlanPackageWithAllocation(value); + break; + case NewPlanUnitWithPercentPrice value: + newPlanUnitWithPercent(value); + break; + case NewPlanMatrixWithAllocationPrice value: + newPlanMatrixWithAllocation(value); + break; + case global::Orb.Models.Plans.TieredWithProration value: + tieredWithProration(value); + break; + case NewPlanUnitWithProrationPrice value: + newPlanUnitWithProration(value); + break; + case NewPlanGroupedAllocationPrice value: + newPlanGroupedAllocation(value); + break; + case NewPlanBulkWithProrationPrice value: + newPlanBulkWithProration(value); + break; + case NewPlanGroupedWithProratedMinimumPrice value: + newPlanGroupedWithProratedMinimum(value); + break; + case NewPlanGroupedWithMeteredMinimumPrice value: + newPlanGroupedWithMeteredMinimum(value); + break; + case global::Orb.Models.Plans.GroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewPlanMatrixWithDisplayNamePrice value: + newPlanMatrixWithDisplayName(value); + break; + case NewPlanGroupedTieredPackagePrice value: + newPlanGroupedTieredPackage(value); + break; + case NewPlanMaxGroupTieredPackagePrice value: + newPlanMaxGroupTieredPackage(value); + break; + case NewPlanScalableMatrixWithUnitPricingPrice value: + newPlanScalableMatrixWithUnitPricing(value); + break; + case NewPlanScalableMatrixWithTieredPricingPrice value: + newPlanScalableMatrixWithTieredPricing(value); + break; + case NewPlanCumulativeGroupedBulkPrice value: + newPlanCumulativeGroupedBulk(value); + break; + case global::Orb.Models.Plans.CumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewPlanMinimumCompositePrice value: + newPlanMinimumComposite(value); + break; + case global::Orb.Models.Plans.Percent value: + percent(value); + break; + case global::Orb.Models.Plans.EventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of PricePrice"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPlanUnitPrice value) => {...}, + /// (NewPlanTieredPrice value) => {...}, + /// (NewPlanBulkPrice value) => {...}, + /// (global::Orb.Models.Plans.BulkWithFilters value) => {...}, + /// (NewPlanPackagePrice value) => {...}, + /// (NewPlanMatrixPrice value) => {...}, + /// (NewPlanThresholdTotalAmountPrice value) => {...}, + /// (NewPlanTieredPackagePrice value) => {...}, + /// (NewPlanTieredWithMinimumPrice value) => {...}, + /// (NewPlanGroupedTieredPrice value) => {...}, + /// (NewPlanTieredPackageWithMinimumPrice value) => {...}, + /// (NewPlanPackageWithAllocationPrice value) => {...}, + /// (NewPlanUnitWithPercentPrice value) => {...}, + /// (NewPlanMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Plans.TieredWithProration value) => {...}, + /// (NewPlanUnitWithProrationPrice value) => {...}, + /// (NewPlanGroupedAllocationPrice value) => {...}, + /// (NewPlanBulkWithProrationPrice value) => {...}, + /// (NewPlanGroupedWithProratedMinimumPrice value) => {...}, + /// (NewPlanGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Plans.GroupedWithMinMaxThresholds value) => {...}, + /// (NewPlanMatrixWithDisplayNamePrice value) => {...}, + /// (NewPlanGroupedTieredPackagePrice value) => {...}, + /// (NewPlanMaxGroupTieredPackagePrice value) => {...}, + /// (NewPlanScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewPlanScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewPlanCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Plans.CumulativeGroupedAllocation value) => {...}, + /// (NewPlanMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Plans.Percent value) => {...}, + /// (global::Orb.Models.Plans.EventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPlanUnit, + System::Func newPlanTiered, + System::Func newPlanBulk, + System::Func bulkWithFilters, + System::Func newPlanPackage, + System::Func newPlanMatrix, + System::Func newPlanThresholdTotalAmount, + System::Func newPlanTieredPackage, + System::Func newPlanTieredWithMinimum, + System::Func newPlanGroupedTiered, + System::Func newPlanTieredPackageWithMinimum, + System::Func newPlanPackageWithAllocation, + System::Func newPlanUnitWithPercent, + System::Func newPlanMatrixWithAllocation, + System::Func tieredWithProration, + System::Func newPlanUnitWithProration, + System::Func newPlanGroupedAllocation, + System::Func newPlanBulkWithProration, + System::Func newPlanGroupedWithProratedMinimum, + System::Func newPlanGroupedWithMeteredMinimum, + System::Func< + global::Orb.Models.Plans.GroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func newPlanMatrixWithDisplayName, + System::Func newPlanGroupedTieredPackage, + System::Func newPlanMaxGroupTieredPackage, + System::Func< + NewPlanScalableMatrixWithUnitPricingPrice, + T + > newPlanScalableMatrixWithUnitPricing, + System::Func< + NewPlanScalableMatrixWithTieredPricingPrice, + T + > newPlanScalableMatrixWithTieredPricing, + System::Func newPlanCumulativeGroupedBulk, + System::Func< + global::Orb.Models.Plans.CumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newPlanMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewPlanUnitPrice value => newPlanUnit(value), + NewPlanTieredPrice value => newPlanTiered(value), + NewPlanBulkPrice value => newPlanBulk(value), + global::Orb.Models.Plans.BulkWithFilters value => bulkWithFilters(value), + NewPlanPackagePrice value => newPlanPackage(value), + NewPlanMatrixPrice value => newPlanMatrix(value), + NewPlanThresholdTotalAmountPrice value => newPlanThresholdTotalAmount(value), + NewPlanTieredPackagePrice value => newPlanTieredPackage(value), + NewPlanTieredWithMinimumPrice value => newPlanTieredWithMinimum(value), + NewPlanGroupedTieredPrice value => newPlanGroupedTiered(value), + NewPlanTieredPackageWithMinimumPrice value => newPlanTieredPackageWithMinimum(value), + NewPlanPackageWithAllocationPrice value => newPlanPackageWithAllocation(value), + NewPlanUnitWithPercentPrice value => newPlanUnitWithPercent(value), + NewPlanMatrixWithAllocationPrice value => newPlanMatrixWithAllocation(value), + global::Orb.Models.Plans.TieredWithProration value => tieredWithProration(value), + NewPlanUnitWithProrationPrice value => newPlanUnitWithProration(value), + NewPlanGroupedAllocationPrice value => newPlanGroupedAllocation(value), + NewPlanBulkWithProrationPrice value => newPlanBulkWithProration(value), + NewPlanGroupedWithProratedMinimumPrice value => newPlanGroupedWithProratedMinimum( + value + ), + NewPlanGroupedWithMeteredMinimumPrice value => newPlanGroupedWithMeteredMinimum(value), + global::Orb.Models.Plans.GroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewPlanMatrixWithDisplayNamePrice value => newPlanMatrixWithDisplayName(value), + NewPlanGroupedTieredPackagePrice value => newPlanGroupedTieredPackage(value), + NewPlanMaxGroupTieredPackagePrice value => newPlanMaxGroupTieredPackage(value), + NewPlanScalableMatrixWithUnitPricingPrice value => newPlanScalableMatrixWithUnitPricing( + value + ), + NewPlanScalableMatrixWithTieredPricingPrice value => + newPlanScalableMatrixWithTieredPricing(value), + NewPlanCumulativeGroupedBulkPrice value => newPlanCumulativeGroupedBulk(value), + global::Orb.Models.Plans.CumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewPlanMinimumCompositePrice value => newPlanMinimumComposite(value), + global::Orb.Models.Plans.Percent value => percent(value), + global::Orb.Models.Plans.EventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of PricePrice"), + }; + } + + public static implicit operator PricePrice(NewPlanUnitPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanTieredPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanBulkPrice value) => new(value); + + public static implicit operator PricePrice(global::Orb.Models.Plans.BulkWithFilters value) => + new(value); + + public static implicit operator PricePrice(NewPlanPackagePrice value) => new(value); + + public static implicit operator PricePrice(NewPlanMatrixPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanThresholdTotalAmountPrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanTieredPackagePrice value) => new(value); + + public static implicit operator PricePrice(NewPlanTieredWithMinimumPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanGroupedTieredPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanTieredPackageWithMinimumPrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanPackageWithAllocationPrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanUnitWithPercentPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanMatrixWithAllocationPrice value) => + new(value); + + public static implicit operator PricePrice( + global::Orb.Models.Plans.TieredWithProration value + ) => new(value); + + public static implicit operator PricePrice(NewPlanUnitWithProrationPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanGroupedAllocationPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanBulkWithProrationPrice value) => new(value); + + public static implicit operator PricePrice(NewPlanGroupedWithProratedMinimumPrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanGroupedWithMeteredMinimumPrice value) => + new(value); + + public static implicit operator PricePrice( + global::Orb.Models.Plans.GroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator PricePrice(NewPlanMatrixWithDisplayNamePrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanGroupedTieredPackagePrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanMaxGroupTieredPackagePrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanScalableMatrixWithUnitPricingPrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanScalableMatrixWithTieredPricingPrice value) => + new(value); + + public static implicit operator PricePrice(NewPlanCumulativeGroupedBulkPrice value) => + new(value); + + public static implicit operator PricePrice( + global::Orb.Models.Plans.CumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator PricePrice(NewPlanMinimumCompositePrice value) => new(value); + + public static implicit operator PricePrice(global::Orb.Models.Plans.Percent value) => + new(value); + + public static implicit operator PricePrice(global::Orb.Models.Plans.EventOutput value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of PricePrice"); + } + this.Switch( + (newPlanUnit) => newPlanUnit.Validate(), + (newPlanTiered) => newPlanTiered.Validate(), + (newPlanBulk) => newPlanBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newPlanPackage) => newPlanPackage.Validate(), + (newPlanMatrix) => newPlanMatrix.Validate(), + (newPlanThresholdTotalAmount) => newPlanThresholdTotalAmount.Validate(), + (newPlanTieredPackage) => newPlanTieredPackage.Validate(), + (newPlanTieredWithMinimum) => newPlanTieredWithMinimum.Validate(), + (newPlanGroupedTiered) => newPlanGroupedTiered.Validate(), + (newPlanTieredPackageWithMinimum) => newPlanTieredPackageWithMinimum.Validate(), + (newPlanPackageWithAllocation) => newPlanPackageWithAllocation.Validate(), + (newPlanUnitWithPercent) => newPlanUnitWithPercent.Validate(), + (newPlanMatrixWithAllocation) => newPlanMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newPlanUnitWithProration) => newPlanUnitWithProration.Validate(), + (newPlanGroupedAllocation) => newPlanGroupedAllocation.Validate(), + (newPlanBulkWithProration) => newPlanBulkWithProration.Validate(), + (newPlanGroupedWithProratedMinimum) => newPlanGroupedWithProratedMinimum.Validate(), + (newPlanGroupedWithMeteredMinimum) => newPlanGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newPlanMatrixWithDisplayName) => newPlanMatrixWithDisplayName.Validate(), + (newPlanGroupedTieredPackage) => newPlanGroupedTieredPackage.Validate(), + (newPlanMaxGroupTieredPackage) => newPlanMaxGroupTieredPackage.Validate(), + (newPlanScalableMatrixWithUnitPricing) => + newPlanScalableMatrixWithUnitPricing.Validate(), + (newPlanScalableMatrixWithTieredPricing) => + newPlanScalableMatrixWithTieredPricing.Validate(), + (newPlanCumulativeGroupedBulk) => newPlanCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newPlanMinimumComposite) => newPlanMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(PricePrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PricePriceConverter : JsonConverter +{ + public override PricePrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PricePrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PricePrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.BulkWithFilters, + global::Orb.Models.Plans.BulkWithFiltersFromRaw + >) +)] +public sealed record class BulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required global::Orb.Models.Plans.BulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Plans.ConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public BulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public BulkWithFilters(global::Orb.Models.Plans.BulkWithFilters bulkWithFilters) + : base(bulkWithFilters) { } + + public BulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.BulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.BulkWithFiltersConfig, + global::Orb.Models.Plans.BulkWithFiltersConfigFromRaw + >) +)] +public sealed record class BulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithFiltersConfig() { } + + public BulkWithFiltersConfig( + global::Orb.Models.Plans.BulkWithFiltersConfig bulkWithFiltersConfig + ) + : base(bulkWithFiltersConfig) { } + + public BulkWithFiltersConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.BulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.Filter, + global::Orb.Models.Plans.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public Filter() { } + + public Filter(global::Orb.Models.Plans.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.Filter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class Tier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public Tier() { } + + public Tier(global::Orb.Models.Plans.Tier tier) + : base(tier) { } + + public Tier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Tier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Tier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class TierFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.Tier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.CadenceConverter))] +public enum Cadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CadenceConverter : JsonConverter +{ + public override global::Orb.Models.Plans.Cadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Plans.Cadence.Annual, + "semi_annual" => global::Orb.Models.Plans.Cadence.SemiAnnual, + "monthly" => global::Orb.Models.Plans.Cadence.Monthly, + "quarterly" => global::Orb.Models.Plans.Cadence.Quarterly, + "one_time" => global::Orb.Models.Plans.Cadence.OneTime, + "custom" => global::Orb.Models.Plans.Cadence.Custom, + _ => (global::Orb.Models.Plans.Cadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.Cadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.Cadence.Annual => "annual", + global::Orb.Models.Plans.Cadence.SemiAnnual => "semi_annual", + global::Orb.Models.Plans.Cadence.Monthly => "monthly", + global::Orb.Models.Plans.Cadence.Quarterly => "quarterly", + global::Orb.Models.Plans.Cadence.OneTime => "one_time", + global::Orb.Models.Plans.Cadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Plans.ConversionRateConfigConverter))] +public record class ConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ConversionRateConfig(SharedUnitConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(SharedTieredConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Plans.ConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Plans.ConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Plans.ConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.ConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Plans.ConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.ConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.TieredWithProration, + global::Orb.Models.Plans.TieredWithProrationFromRaw + >) +)] +public sealed record class TieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required global::Orb.Models.Plans.TieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Plans.TieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public TieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public TieredWithProration(global::Orb.Models.Plans.TieredWithProration tieredWithProration) + : base(tieredWithProration) { } + + public TieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.TieredWithProration.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.TieredWithProrationCadenceConverter))] +public enum TieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class TieredWithProrationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.TieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Plans.TieredWithProrationCadence.Annual, + "semi_annual" => global::Orb.Models.Plans.TieredWithProrationCadence.SemiAnnual, + "monthly" => global::Orb.Models.Plans.TieredWithProrationCadence.Monthly, + "quarterly" => global::Orb.Models.Plans.TieredWithProrationCadence.Quarterly, + "one_time" => global::Orb.Models.Plans.TieredWithProrationCadence.OneTime, + "custom" => global::Orb.Models.Plans.TieredWithProrationCadence.Custom, + _ => (global::Orb.Models.Plans.TieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.TieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.TieredWithProrationCadence.Annual => "annual", + global::Orb.Models.Plans.TieredWithProrationCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Plans.TieredWithProrationCadence.Monthly => "monthly", + global::Orb.Models.Plans.TieredWithProrationCadence.Quarterly => "quarterly", + global::Orb.Models.Plans.TieredWithProrationCadence.OneTime => "one_time", + global::Orb.Models.Plans.TieredWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.TieredWithProrationConfig, + global::Orb.Models.Plans.TieredWithProrationConfigFromRaw + >) +)] +public sealed record class TieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredWithProrationConfig() { } + + public TieredWithProrationConfig( + global::Orb.Models.Plans.TieredWithProrationConfig tieredWithProrationConfig + ) + : base(tieredWithProrationConfig) { } + + public TieredWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Plans.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.TieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.TieredWithProrationConfigTier, + global::Orb.Models.Plans.TieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class TieredWithProrationConfigTier : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithProrationConfigTier() { } + + public TieredWithProrationConfigTier( + global::Orb.Models.Plans.TieredWithProrationConfigTier tieredWithProrationConfigTier + ) + : base(tieredWithProrationConfigTier) { } + + public TieredWithProrationConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Plans.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.TieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Plans.TieredWithProrationConversionRateConfigConverter))] +public record class TieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Plans.TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Plans.TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Plans.TieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.TieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Plans.TieredWithProrationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.TieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.GroupedWithMinMaxThresholds, + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public GroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public GroupedWithMinMaxThresholds( + global::Orb.Models.Plans.GroupedWithMinMaxThresholds groupedWithMinMaxThresholds + ) + : base(groupedWithMinMaxThresholds) { } + + public GroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Plans.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.GroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadenceConverter))] +public enum GroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class GroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Custom, + _ => (global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Annual => "annual", + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Quarterly => + "quarterly", + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfig, + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsConfig : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public GroupedWithMinMaxThresholdsConfig() { } + + public GroupedWithMinMaxThresholdsConfig( + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfig groupedWithMinMaxThresholdsConfig + ) + : base(groupedWithMinMaxThresholdsConfig) { } + + public GroupedWithMinMaxThresholdsConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class GroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.GroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.CumulativeGroupedAllocation, + global::Orb.Models.Plans.CumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required global::Orb.Models.Plans.CumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public CumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public CumulativeGroupedAllocation( + global::Orb.Models.Plans.CumulativeGroupedAllocation cumulativeGroupedAllocation + ) + : base(cumulativeGroupedAllocation) { } + + public CumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Plans.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.CumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.CumulativeGroupedAllocationCadenceConverter))] +public enum CumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.CumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Annual, + "semi_annual" => global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Monthly, + "quarterly" => global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Quarterly, + "one_time" => global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.OneTime, + "custom" => global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Custom, + _ => (global::Orb.Models.Plans.CumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Annual => "annual", + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Monthly => "monthly", + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Quarterly => + "quarterly", + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.OneTime => "one_time", + global::Orb.Models.Plans.CumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.CumulativeGroupedAllocationConfig, + global::Orb.Models.Plans.CumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationConfig : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public CumulativeGroupedAllocationConfig() { } + + public CumulativeGroupedAllocationConfig( + global::Orb.Models.Plans.CumulativeGroupedAllocationConfig cumulativeGroupedAllocationConfig + ) + : base(cumulativeGroupedAllocationConfig) { } + + public CumulativeGroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Plans.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.CumulativeGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class CumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.CumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.Percent, + global::Orb.Models.Plans.PercentFromRaw + >) +)] +public sealed record class Percent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required global::Orb.Models.Plans.PercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Plans.PercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public Percent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public Percent(global::Orb.Models.Plans.Percent percent) + : base(percent) { } + + public Percent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.Percent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.PercentCadenceConverter))] +public enum PercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PercentCadenceConverter : JsonConverter +{ + public override global::Orb.Models.Plans.PercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Plans.PercentCadence.Annual, + "semi_annual" => global::Orb.Models.Plans.PercentCadence.SemiAnnual, + "monthly" => global::Orb.Models.Plans.PercentCadence.Monthly, + "quarterly" => global::Orb.Models.Plans.PercentCadence.Quarterly, + "one_time" => global::Orb.Models.Plans.PercentCadence.OneTime, + "custom" => global::Orb.Models.Plans.PercentCadence.Custom, + _ => (global::Orb.Models.Plans.PercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.PercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.PercentCadence.Annual => "annual", + global::Orb.Models.Plans.PercentCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Plans.PercentCadence.Monthly => "monthly", + global::Orb.Models.Plans.PercentCadence.Quarterly => "quarterly", + global::Orb.Models.Plans.PercentCadence.OneTime => "one_time", + global::Orb.Models.Plans.PercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.PercentConfig, + global::Orb.Models.Plans.PercentConfigFromRaw + >) +)] +public sealed record class PercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PercentConfig() { } + + public PercentConfig(global::Orb.Models.Plans.PercentConfig percentConfig) + : base(percentConfig) { } + + public PercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PercentConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.PercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Plans.PercentConversionRateConfigConverter))] +public record class PercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Plans.PercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Plans.PercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Plans.PercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PercentConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.PercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Plans.PercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.PercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.EventOutput, + global::Orb.Models.Plans.EventOutputFromRaw + >) +)] +public sealed record class EventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required global::Orb.Models.Plans.EventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Plans.EventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public EventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public EventOutput(global::Orb.Models.Plans.EventOutput eventOutput) + : base(eventOutput) { } + + public EventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.EventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.EventOutputCadenceConverter))] +public enum EventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class EventOutputCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.EventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Plans.EventOutputCadence.Annual, + "semi_annual" => global::Orb.Models.Plans.EventOutputCadence.SemiAnnual, + "monthly" => global::Orb.Models.Plans.EventOutputCadence.Monthly, + "quarterly" => global::Orb.Models.Plans.EventOutputCadence.Quarterly, + "one_time" => global::Orb.Models.Plans.EventOutputCadence.OneTime, + "custom" => global::Orb.Models.Plans.EventOutputCadence.Custom, + _ => (global::Orb.Models.Plans.EventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.EventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.EventOutputCadence.Annual => "annual", + global::Orb.Models.Plans.EventOutputCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Plans.EventOutputCadence.Monthly => "monthly", + global::Orb.Models.Plans.EventOutputCadence.Quarterly => "quarterly", + global::Orb.Models.Plans.EventOutputCadence.OneTime => "one_time", + global::Orb.Models.Plans.EventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Plans.EventOutputConfig, + global::Orb.Models.Plans.EventOutputConfigFromRaw + >) +)] +public sealed record class EventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public EventOutputConfig() { } + + public EventOutputConfig(global::Orb.Models.Plans.EventOutputConfig eventOutputConfig) + : base(eventOutputConfig) { } + + public EventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class EventOutputConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.EventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Plans.EventOutputConversionRateConfigConverter))] +public record class EventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Plans.EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Plans.EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Plans.EventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EventOutputConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Plans.EventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Plans.EventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.EventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Adjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the plan. + /// + public required AdjustmentAdjustment AdjustmentValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment"); } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The phase to add this adjustment to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + public override void Validate() + { + this.AdjustmentValue.Validate(); + _ = this.PlanPhaseOrder; + } + + public Adjustment() { } + + public Adjustment(global::Orb.Models.Plans.Adjustment adjustment) + : base(adjustment) { } + + public Adjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Adjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Plans.Adjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Adjustment(AdjustmentAdjustment adjustmentValue) + : this() + { + this.AdjustmentValue = adjustmentValue; + } +} + +class AdjustmentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Plans.Adjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Plans.Adjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the plan. +/// +[JsonConverter(typeof(AdjustmentAdjustmentConverter))] +public record class AdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public AdjustmentAdjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public AdjustmentAdjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public AdjustmentAdjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public AdjustmentAdjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public AdjustmentAdjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public AdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of AdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of AdjustmentAdjustment" + ), + }; + } + + public static implicit operator AdjustmentAdjustment(NewPercentageDiscount value) => new(value); + + public static implicit operator AdjustmentAdjustment(NewUsageDiscount value) => new(value); + + public static implicit operator AdjustmentAdjustment(NewAmountDiscount value) => new(value); + + public static implicit operator AdjustmentAdjustment(NewMinimum value) => new(value); + + public static implicit operator AdjustmentAdjustment(NewMaximum value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of AdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(AdjustmentAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentAdjustmentConverter : JsonConverter +{ + public override AdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new AdjustmentAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + AdjustmentAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PlanPhase : JsonModel +{ + /// + /// Determines the ordering of the phase in a plan's lifecycle. 1 = first phase. + /// + public required long Order + { + get { return JsonModel.GetNotNullStruct(this.RawData, "order"); } + init { JsonModel.Set(this._rawData, "order", value); } + } + + /// + /// Align billing cycle day with phase start date. + /// + public bool? AlignBillingWithPhaseStartDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "align_billing_with_phase_start_date" + ); + } + init { JsonModel.Set(this._rawData, "align_billing_with_phase_start_date", value); } + } + + /// + /// How many terms of length `duration_unit` this phase is active for. If null, + /// this phase is evergreen and active indefinitely + /// + public long? Duration + { + get { return JsonModel.GetNullableStruct(this.RawData, "duration"); } + init { JsonModel.Set(this._rawData, "duration", value); } + } + + public ApiEnum? DurationUnit + { + get + { + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawData, "duration_unit"); + } + init { JsonModel.Set(this._rawData, "duration_unit", value); } + } + + /// + public override void Validate() + { + _ = this.Order; + _ = this.AlignBillingWithPhaseStartDate; + _ = this.Duration; + this.DurationUnit?.Validate(); + } + + public PlanPhase() { } + + public PlanPhase(PlanPhase planPhase) + : base(planPhase) { } + + public PlanPhase(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanPhase(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PlanPhase FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PlanPhase(long order) + : this() + { + this.Order = order; + } +} + +class PlanPhaseFromRaw : IFromRawJson +{ + /// + public PlanPhase FromRawUnchecked(IReadOnlyDictionary rawData) => + PlanPhase.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Plans.DurationUnitConverter))] +public enum DurationUnit +{ + Daily, + Monthly, + Quarterly, + SemiAnnual, + Annual, +} + +sealed class DurationUnitConverter : JsonConverter +{ + public override global::Orb.Models.Plans.DurationUnit Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "daily" => global::Orb.Models.Plans.DurationUnit.Daily, + "monthly" => global::Orb.Models.Plans.DurationUnit.Monthly, + "quarterly" => global::Orb.Models.Plans.DurationUnit.Quarterly, + "semi_annual" => global::Orb.Models.Plans.DurationUnit.SemiAnnual, + "annual" => global::Orb.Models.Plans.DurationUnit.Annual, + _ => (global::Orb.Models.Plans.DurationUnit)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.DurationUnit value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.DurationUnit.Daily => "daily", + global::Orb.Models.Plans.DurationUnit.Monthly => "monthly", + global::Orb.Models.Plans.DurationUnit.Quarterly => "quarterly", + global::Orb.Models.Plans.DurationUnit.SemiAnnual => "semi_annual", + global::Orb.Models.Plans.DurationUnit.Annual => "annual", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The status of the plan to create (either active or draft). If not specified, +/// this defaults to active. +/// +[JsonConverter(typeof(global::Orb.Models.Plans.StatusConverter))] +public enum Status +{ + Active, + Draft, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.Plans.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => global::Orb.Models.Plans.Status.Active, + "draft" => global::Orb.Models.Plans.Status.Draft, + _ => (global::Orb.Models.Plans.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Plans.Status value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Plans.Status.Active => "active", + global::Orb.Models.Plans.Status.Draft => "draft", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } } diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/Adjustment.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/Adjustment.cs deleted file mode 100644 index caaed4af..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/Adjustment.cs +++ /dev/null @@ -1,73 +0,0 @@ -using AdjustmentProperties = Orb.Models.Plans.PlanCreateParamsProperties.AdjustmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Adjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the plan. - /// - public required AdjustmentProperties::Adjustment Adjustment1 - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this adjustment to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.Adjustment1.Validate(); - _ = this.PlanPhaseOrder; - } - - public Adjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Adjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Adjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/AdjustmentProperties/Adjustment.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/AdjustmentProperties/Adjustment.cs deleted file mode 100644 index 89aa6a52..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/AdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Plans.PlanCreateParamsProperties.AdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanCreateParamsProperties.AdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the plan. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/AdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/AdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 32d4d4a6..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/AdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using AdjustmentProperties = Orb.Models.Plans.PlanCreateParamsProperties.AdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanCreateParamsProperties.AdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : AdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : AdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : AdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : AdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : AdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/PlanPhase.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/PlanPhase.cs deleted file mode 100644 index c198cfe0..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/PlanPhase.cs +++ /dev/null @@ -1,105 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PlanPhaseProperties = Orb.Models.Plans.PlanCreateParamsProperties.PlanPhaseProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhase : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Determines the ordering of the phase in a plan's lifecycle. 1 = first phase. - /// - public required long Order - { - get - { - if (!this.Properties.TryGetValue("order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("order", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["order"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Align billing cycle day with phase start date. - /// - public bool? AlignBillingWithPhaseStartDate - { - get - { - if ( - !this.Properties.TryGetValue( - "align_billing_with_phase_start_date", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["align_billing_with_phase_start_date"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// How many terms of length `duration_unit` this phase is active for. If null, - /// this phase is evergreen and active indefinitely - /// - public long? Duration - { - get - { - if (!this.Properties.TryGetValue("duration", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public PlanPhaseProperties::DurationUnit? DurationUnit - { - get - { - if (!this.Properties.TryGetValue("duration_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration_unit"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Order; - _ = this.AlignBillingWithPhaseStartDate; - _ = this.Duration; - this.DurationUnit?.Validate(); - } - - public PlanPhase() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhase(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PlanPhase FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/PlanPhaseProperties/DurationUnit.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/PlanPhaseProperties/DurationUnit.cs deleted file mode 100644 index 33054270..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/PlanPhaseProperties/DurationUnit.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanCreateParamsProperties.PlanPhaseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DurationUnit(string value) : Orb::IEnum -{ - public static readonly DurationUnit Daily = new("daily"); - - public static readonly DurationUnit Monthly = new("monthly"); - - public static readonly DurationUnit Quarterly = new("quarterly"); - - public static readonly DurationUnit SemiAnnual = new("semi_annual"); - - public static readonly DurationUnit Annual = new("annual"); - - readonly string _value = value; - - public enum Value - { - Daily, - Monthly, - Quarterly, - SemiAnnual, - Annual, - } - - public Value Known() => - _value switch - { - "daily" => Value.Daily, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DurationUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/Price.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/Price.cs deleted file mode 100644 index 55bad9a4..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/Price.cs +++ /dev/null @@ -1,86 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using PriceProperties = Orb.Models.Plans.PlanCreateParamsProperties.PriceProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Price : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The allocation price to add to the plan. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The phase to add this price to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The price to add to the plan - /// - public PriceProperties::Price? Price1 - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.AllocationPrice?.Validate(); - _ = this.PlanPhaseOrder; - this.Price1?.Validate(); - } - - public Price() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Price(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Price FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/PriceProperties/Price.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/PriceProperties/Price.cs deleted file mode 100644 index d0f2f60b..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/PriceProperties/Price.cs +++ /dev/null @@ -1,122 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Plans.PlanCreateParamsProperties.PriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanCreateParamsProperties.PriceProperties; - -/// -/// The price to add to the plan -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewPlanUnitPrice Create(Models::NewPlanUnitPrice value) => - new(value); - - public static PriceVariants::NewPlanPackagePrice Create(Models::NewPlanPackagePrice value) => - new(value); - - public static PriceVariants::NewPlanMatrixPrice Create(Models::NewPlanMatrixPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredPrice Create(Models::NewPlanTieredPrice value) => - new(value); - - public static PriceVariants::NewPlanTieredBPSPrice Create( - Models::NewPlanTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewPlanBPSPrice Create(Models::NewPlanBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkBPSPrice Create(Models::NewPlanBulkBPSPrice value) => - new(value); - - public static PriceVariants::NewPlanBulkPrice Create(Models::NewPlanBulkPrice value) => - new(value); - - public static PriceVariants::NewPlanThresholdTotalAmountPrice Create( - Models::NewPlanThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackagePrice Create( - Models::NewPlanTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredWithMinimumPrice Create( - Models::NewPlanTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithPercentPrice Create( - Models::NewPlanUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewPlanPackageWithAllocationPrice Create( - Models::NewPlanPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanTierWithProrationPrice Create( - Models::NewPlanTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanUnitWithProrationPrice Create( - Models::NewPlanUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedAllocationPrice Create( - Models::NewPlanGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithProratedMinimumPrice Create( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedWithMeteredMinimumPrice Create( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithDisplayNamePrice Create( - Models::NewPlanMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewPlanBulkWithProrationPrice Create( - Models::NewPlanBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPackagePrice Create( - Models::NewPlanGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanMaxGroupTieredPackagePrice Create( - Models::NewPlanMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithUnitPricingPrice Create( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanScalableMatrixWithTieredPricingPrice Create( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewPlanCumulativeGroupedBulkPrice Create( - Models::NewPlanCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewPlanTieredPackageWithMinimumPrice Create( - Models::NewPlanTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewPlanMatrixWithAllocationPrice Create( - Models::NewPlanMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewPlanGroupedTieredPrice Create( - Models::NewPlanGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/PriceProperties/PriceVariants/All.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/PriceProperties/PriceVariants/All.cs deleted file mode 100644 index 670d536f..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/PriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,634 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceProperties = Orb.Models.Plans.PlanCreateParamsProperties.PriceProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanCreateParamsProperties.PriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitPrice(Models::NewPlanUnitPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitPrice From(Models::NewPlanUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanPackagePrice(Models::NewPlanPackagePrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackagePrice From(Models::NewPlanPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanMatrixPrice(Models::NewPlanMatrixPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixPrice From(Models::NewPlanMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPrice(Models::NewPlanTieredPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPrice From(Models::NewPlanTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredBPSPrice(Models::NewPlanTieredBPSPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredBPSPrice From(Models::NewPlanTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBPSPrice(Models::NewPlanBPSPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBPSPrice From(Models::NewPlanBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkBPSPrice(Models::NewPlanBulkBPSPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkBPSPrice From(Models::NewPlanBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanBulkPrice(Models::NewPlanBulkPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkPrice From(Models::NewPlanBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanThresholdTotalAmountPrice, - Models::NewPlanThresholdTotalAmountPrice - >) -)] -public sealed record class NewPlanThresholdTotalAmountPrice( - Models::NewPlanThresholdTotalAmountPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanThresholdTotalAmountPrice From( - Models::NewPlanThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanTieredPackagePrice(Models::NewPlanTieredPackagePrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredPackagePrice From(Models::NewPlanTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredWithMinimumPrice, - Models::NewPlanTieredWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredWithMinimumPrice( - Models::NewPlanTieredWithMinimumPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTieredWithMinimumPrice From(Models::NewPlanTieredWithMinimumPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanUnitWithPercentPrice(Models::NewPlanUnitWithPercentPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithPercentPrice From(Models::NewPlanUnitWithPercentPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanPackageWithAllocationPrice, - Models::NewPlanPackageWithAllocationPrice - >) -)] -public sealed record class NewPlanPackageWithAllocationPrice( - Models::NewPlanPackageWithAllocationPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanPackageWithAllocationPrice From( - Models::NewPlanPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTierWithProrationPrice, - Models::NewPlanTierWithProrationPrice - >) -)] -public sealed record class NewPlanTierWithProrationPrice( - Models::NewPlanTierWithProrationPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanTierWithProrationPrice From(Models::NewPlanTierWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanUnitWithProrationPrice, - Models::NewPlanUnitWithProrationPrice - >) -)] -public sealed record class NewPlanUnitWithProrationPrice( - Models::NewPlanUnitWithProrationPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanUnitWithProrationPrice From(Models::NewPlanUnitWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedAllocationPrice, - Models::NewPlanGroupedAllocationPrice - >) -)] -public sealed record class NewPlanGroupedAllocationPrice( - Models::NewPlanGroupedAllocationPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedAllocationPrice From(Models::NewPlanGroupedAllocationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithProratedMinimumPrice( - Models::NewPlanGroupedWithProratedMinimumPrice Value -) - : PriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithProratedMinimumPrice, - Models::NewPlanGroupedWithProratedMinimumPrice - > -{ - public static NewPlanGroupedWithProratedMinimumPrice From( - Models::NewPlanGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewPlanGroupedWithMeteredMinimumPrice( - Models::NewPlanGroupedWithMeteredMinimumPrice Value -) - : PriceProperties::Price, - Orb::IVariant< - NewPlanGroupedWithMeteredMinimumPrice, - Models::NewPlanGroupedWithMeteredMinimumPrice - > -{ - public static NewPlanGroupedWithMeteredMinimumPrice From( - Models::NewPlanGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithDisplayNamePrice, - Models::NewPlanMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewPlanMatrixWithDisplayNamePrice( - Models::NewPlanMatrixWithDisplayNamePrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithDisplayNamePrice From( - Models::NewPlanMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanBulkWithProrationPrice, - Models::NewPlanBulkWithProrationPrice - >) -)] -public sealed record class NewPlanBulkWithProrationPrice( - Models::NewPlanBulkWithProrationPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanBulkWithProrationPrice From(Models::NewPlanBulkWithProrationPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanGroupedTieredPackagePrice, - Models::NewPlanGroupedTieredPackagePrice - >) -)] -public sealed record class NewPlanGroupedTieredPackagePrice( - Models::NewPlanGroupedTieredPackagePrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPackagePrice From( - Models::NewPlanGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMaxGroupTieredPackagePrice, - Models::NewPlanMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewPlanMaxGroupTieredPackagePrice( - Models::NewPlanMaxGroupTieredPackagePrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMaxGroupTieredPackagePrice From( - Models::NewPlanMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithUnitPricingPrice( - Models::NewPlanScalableMatrixWithUnitPricingPrice Value -) - : PriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithUnitPricingPrice, - Models::NewPlanScalableMatrixWithUnitPricingPrice - > -{ - public static NewPlanScalableMatrixWithUnitPricingPrice From( - Models::NewPlanScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewPlanScalableMatrixWithTieredPricingPrice( - Models::NewPlanScalableMatrixWithTieredPricingPrice Value -) - : PriceProperties::Price, - Orb::IVariant< - NewPlanScalableMatrixWithTieredPricingPrice, - Models::NewPlanScalableMatrixWithTieredPricingPrice - > -{ - public static NewPlanScalableMatrixWithTieredPricingPrice From( - Models::NewPlanScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanCumulativeGroupedBulkPrice, - Models::NewPlanCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewPlanCumulativeGroupedBulkPrice( - Models::NewPlanCumulativeGroupedBulkPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanCumulativeGroupedBulkPrice From( - Models::NewPlanCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewPlanTieredPackageWithMinimumPrice( - Models::NewPlanTieredPackageWithMinimumPrice Value -) - : PriceProperties::Price, - Orb::IVariant< - NewPlanTieredPackageWithMinimumPrice, - Models::NewPlanTieredPackageWithMinimumPrice - > -{ - public static NewPlanTieredPackageWithMinimumPrice From( - Models::NewPlanTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewPlanMatrixWithAllocationPrice, - Models::NewPlanMatrixWithAllocationPrice - >) -)] -public sealed record class NewPlanMatrixWithAllocationPrice( - Models::NewPlanMatrixWithAllocationPrice Value -) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanMatrixWithAllocationPrice From( - Models::NewPlanMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPlanGroupedTieredPrice(Models::NewPlanGroupedTieredPrice Value) - : PriceProperties::Price, - Orb::IVariant -{ - public static NewPlanGroupedTieredPrice From(Models::NewPlanGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Plans/PlanCreateParamsProperties/Status.cs b/src/Orb/Models/Plans/PlanCreateParamsProperties/Status.cs deleted file mode 100644 index 48186f3b..00000000 --- a/src/Orb/Models/Plans/PlanCreateParamsProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanCreateParamsProperties; - -/// -/// The status of the plan to create (either active or draft). If not specified, this -/// defaults to active. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Draft = new("draft"); - - readonly string _value = value; - - public enum Value - { - Active, - Draft, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "draft" => Value.Draft, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/PlanFetchParams.cs b/src/Orb/Models/Plans/PlanFetchParams.cs index 95823a0f..15fcf7fa 100644 --- a/src/Orb/Models/Plans/PlanFetchParams.cs +++ b/src/Orb/Models/Plans/PlanFetchParams.cs @@ -1,42 +1,84 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Plans; /// -/// This endpoint is used to fetch [plan](/core-concepts#plan-and-price) details given -/// a plan identifier. It returns information about the prices included in the plan -/// and their configuration, as well as the product that the plan is attached to. +/// This endpoint is used to fetch [plan](/core-concepts#plan-and-price) details +/// given a plan identifier. It returns information about the prices included in +/// the plan and their configuration, as well as the product that the plan is attached to. /// -/// ## Serialized prices Orb supports a few different pricing models out of the box. -/// Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) +/// ## Serialized prices Orb supports a few different pricing models out of +/// the box. Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) /// object. The `model_type` field determines the key for the configuration object -/// that is present. A detailed explanation of price types can be found in the [Price schema](/core-concepts#plan-and-price). +/// that is present. A detailed explanation of price types can be found in the [Price schema](/core-concepts#plan-and-price). /// -/// ## Phases Orb supports plan phases, also known as contract ramps. For plans with -/// phases, the serialized prices refer to all prices across all phases. +/// ## Phases Orb supports plan phases, also known as contract ramps. For plans +/// with phases, the serialized prices refer to all prices across all phases. /// -public sealed record class PlanFetchParams : Orb::ParamsBase +public sealed record class PlanFetchParams : ParamsBase { - public required string PlanID; + public string? PlanID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public PlanFetchParams() { } + + public PlanFetchParams(PlanFetchParams planFetchParams) + : base(planFetchParams) { } + + public PlanFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static PlanFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/{0}", this.PlanID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/{0}", this.PlanID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Plans/PlanListPage.cs b/src/Orb/Models/Plans/PlanListPage.cs new file mode 100644 index 00000000..0bf4d880 --- /dev/null +++ b/src/Orb/Models/Plans/PlanListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Plans; + +public sealed class PlanListPage( + IPlanService service, + PlanListParams parameters, + PlanListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Plans/PlanListPageResponse.cs b/src/Orb/Models/Plans/PlanListPageResponse.cs index 2dbec544..0fec8f00 100644 --- a/src/Orb/Models/Plans/PlanListPageResponse.cs +++ b/src/Orb/Models/Plans/PlanListPageResponse.cs @@ -1,50 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Plans; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PlanListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +40,35 @@ public override void Validate() public PlanListPageResponse() { } + public PlanListPageResponse(PlanListPageResponse planListPageResponse) + : base(planListPageResponse) { } + + public PlanListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + PlanListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PlanListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class PlanListPageResponseFromRaw : IFromRawJson +{ + /// + public PlanListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PlanListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Plans/PlanListParams.cs b/src/Orb/Models/Plans/PlanListParams.cs index 7ad8f9ba..f11dc700 100644 --- a/src/Orb/Models/Plans/PlanListParams.cs +++ b/src/Orb/Models/Plans/PlanListParams.cs @@ -1,7 +1,11 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using PlanListParamsProperties = Orb.Models.Plans.PlanListParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Plans; @@ -12,70 +16,54 @@ namespace Orb.Models.Plans; /// recently created plan. The response also includes [`pagination_metadata`](/api-reference/pagination), /// which lets the caller retrieve the next page of results if they exist. /// -public sealed record class PlanListParams : Orb::ParamsBase +public sealed record class PlanListParams : ParamsBase { - public System::DateTime? CreatedAtGt + public System::DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public System::DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public System::DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public System::DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -84,14 +72,8 @@ public sealed record class PlanListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -99,45 +81,143 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } /// /// The plan status to filter to ('active', 'archived', or 'draft'). /// - public PlanListParamsProperties::Status? Status + public ApiEnum? Status { get { - if (!this.QueryProperties.TryGetValue("status", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableClass>( + this.RawQueryData, + "status" + ); + } + init + { + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "status", value); } - set { this.QueryProperties["status"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public PlanListParams() { } + + public PlanListParams(PlanListParams planListParams) + : base(planListParams) { } + + public PlanListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/plans") + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static PlanListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/plans") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// The plan status to filter to ('active', 'archived', or 'draft'). +/// +[JsonConverter(typeof(PlanListParamsStatusConverter))] +public enum PlanListParamsStatus +{ + Active, + Archived, + Draft, +} + +sealed class PlanListParamsStatusConverter : JsonConverter +{ + public override PlanListParamsStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => PlanListParamsStatus.Active, + "archived" => PlanListParamsStatus.Archived, + "draft" => PlanListParamsStatus.Draft, + _ => (PlanListParamsStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PlanListParamsStatus value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PlanListParamsStatus.Active => "active", + PlanListParamsStatus.Archived => "archived", + PlanListParamsStatus.Draft => "draft", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Plans/PlanListParamsProperties/Status.cs b/src/Orb/Models/Plans/PlanListParamsProperties/Status.cs deleted file mode 100644 index 187f1898..00000000 --- a/src/Orb/Models/Plans/PlanListParamsProperties/Status.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanListParamsProperties; - -/// -/// The plan status to filter to ('active', 'archived', or 'draft'). -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Archived = new("archived"); - - public static readonly Status Draft = new("draft"); - - readonly string _value = value; - - public enum Value - { - Active, - Archived, - Draft, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "archived" => Value.Archived, - "draft" => Value.Draft, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/Adjustment.cs b/src/Orb/Models/Plans/PlanProperties/Adjustment.cs deleted file mode 100644 index 85e5a339..00000000 --- a/src/Orb/Models/Plans/PlanProperties/Adjustment.cs +++ /dev/null @@ -1,34 +0,0 @@ -using AdjustmentVariants = Orb.Models.Plans.PlanProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::PlanPhaseUsageDiscountAdjustment Create( - Models::PlanPhaseUsageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseAmountDiscountAdjustment Create( - Models::PlanPhaseAmountDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhasePercentageDiscountAdjustment Create( - Models::PlanPhasePercentageDiscountAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseMinimumAdjustment Create( - Models::PlanPhaseMinimumAdjustment value - ) => new(value); - - public static AdjustmentVariants::PlanPhaseMaximumAdjustment Create( - Models::PlanPhaseMaximumAdjustment value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Plans/PlanProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Plans/PlanProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 8c21eff0..00000000 --- a/src/Orb/Models/Plans/PlanProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,120 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PlanProperties = Orb.Models.Plans.PlanProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Plans.PlanProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhaseUsageDiscountAdjustment, - Models::PlanPhaseUsageDiscountAdjustment - >) -)] -public sealed record class PlanPhaseUsageDiscountAdjustment( - Models::PlanPhaseUsageDiscountAdjustment Value -) - : PlanProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseUsageDiscountAdjustment From( - Models::PlanPhaseUsageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhaseAmountDiscountAdjustment, - Models::PlanPhaseAmountDiscountAdjustment - >) -)] -public sealed record class PlanPhaseAmountDiscountAdjustment( - Models::PlanPhaseAmountDiscountAdjustment Value -) - : PlanProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseAmountDiscountAdjustment From( - Models::PlanPhaseAmountDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - PlanPhasePercentageDiscountAdjustment, - Models::PlanPhasePercentageDiscountAdjustment - >) -)] -public sealed record class PlanPhasePercentageDiscountAdjustment( - Models::PlanPhasePercentageDiscountAdjustment Value -) - : PlanProperties::Adjustment, - Orb::IVariant< - PlanPhasePercentageDiscountAdjustment, - Models::PlanPhasePercentageDiscountAdjustment - > -{ - public static PlanPhasePercentageDiscountAdjustment From( - Models::PlanPhasePercentageDiscountAdjustment value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PlanPhaseMinimumAdjustment(Models::PlanPhaseMinimumAdjustment Value) - : PlanProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseMinimumAdjustment From(Models::PlanPhaseMinimumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PlanPhaseMaximumAdjustment(Models::PlanPhaseMaximumAdjustment Value) - : PlanProperties::Adjustment, - Orb::IVariant -{ - public static PlanPhaseMaximumAdjustment From(Models::PlanPhaseMaximumAdjustment value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/BasePlan.cs b/src/Orb/Models/Plans/PlanProperties/BasePlan.cs deleted file mode 100644 index 64dc97ce..00000000 --- a/src/Orb/Models/Plans/PlanProperties/BasePlan.cs +++ /dev/null @@ -1,83 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BasePlan : Orb::ModelBase, Orb::IFromRaw -{ - public required string? ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional user-defined ID for this plan resource, used throughout the system - /// as an alias for this Plan. Use this field to identify a plan by an existing - /// identifier in your system. - /// - public required string? ExternalPlanID - { - get - { - if (!this.Properties.TryGetValue("external_plan_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_plan_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_plan_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string? Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.ExternalPlanID; - _ = this.Name; - } - - public BasePlan() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BasePlan(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BasePlan FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/PlanPhase.cs b/src/Orb/Models/Plans/PlanProperties/PlanPhase.cs deleted file mode 100644 index f1a5274e..00000000 --- a/src/Orb/Models/Plans/PlanProperties/PlanPhase.cs +++ /dev/null @@ -1,211 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using PlanPhaseProperties = Orb.Models.Plans.PlanProperties.PlanPhaseProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PlanPhase : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? Description - { - get - { - if (!this.Properties.TryGetValue("description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["description"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// How many terms of length `duration_unit` this phase is active for. If null, - /// this phase is evergreen and active indefinitely - /// - public required long? Duration - { - get - { - if (!this.Properties.TryGetValue("duration", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required PlanPhaseProperties::DurationUnit? DurationUnit - { - get - { - if (!this.Properties.TryGetValue("duration_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "duration_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["duration_unit"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Determines the ordering of the phase in a plan's lifecycle. 1 = first phase. - /// - public required long Order - { - get - { - if (!this.Properties.TryGetValue("order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("order", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["order"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Description; - this.Discount?.Validate(); - _ = this.Duration; - this.DurationUnit?.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - this.Minimum?.Validate(); - _ = this.MinimumAmount; - _ = this.Name; - _ = this.Order; - } - - public PlanPhase() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PlanPhase(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PlanPhase FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/PlanPhaseProperties/DurationUnit.cs b/src/Orb/Models/Plans/PlanProperties/PlanPhaseProperties/DurationUnit.cs deleted file mode 100644 index 4cea5df1..00000000 --- a/src/Orb/Models/Plans/PlanProperties/PlanPhaseProperties/DurationUnit.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanProperties.PlanPhaseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DurationUnit(string value) : Orb::IEnum -{ - public static readonly DurationUnit Daily = new("daily"); - - public static readonly DurationUnit Monthly = new("monthly"); - - public static readonly DurationUnit Quarterly = new("quarterly"); - - public static readonly DurationUnit SemiAnnual = new("semi_annual"); - - public static readonly DurationUnit Annual = new("annual"); - - readonly string _value = value; - - public enum Value - { - Daily, - Monthly, - Quarterly, - SemiAnnual, - Annual, - } - - public Value Known() => - _value switch - { - "daily" => Value.Daily, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DurationUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/Product.cs b/src/Orb/Models/Plans/PlanProperties/Product.cs deleted file mode 100644 index 7aae4f67..00000000 --- a/src/Orb/Models/Plans/PlanProperties/Product.cs +++ /dev/null @@ -1,77 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Product : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.CreatedAt; - _ = this.Name; - } - - public Product() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Product(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Product FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/Status.cs b/src/Orb/Models/Plans/PlanProperties/Status.cs deleted file mode 100644 index 04d48a3a..00000000 --- a/src/Orb/Models/Plans/PlanProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Archived = new("archived"); - - public static readonly Status Draft = new("draft"); - - readonly string _value = value; - - public enum Value - { - Active, - Archived, - Draft, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "archived" => Value.Archived, - "draft" => Value.Draft, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/TrialConfig.cs b/src/Orb/Models/Plans/PlanProperties/TrialConfig.cs deleted file mode 100644 index 4bb4de54..00000000 --- a/src/Orb/Models/Plans/PlanProperties/TrialConfig.cs +++ /dev/null @@ -1,70 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TrialConfigProperties = Orb.Models.Plans.PlanProperties.TrialConfigProperties; - -namespace Orb.Models.Plans.PlanProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TrialConfig : Orb::ModelBase, Orb::IFromRaw -{ - public required long? TrialPeriod - { - get - { - if (!this.Properties.TryGetValue("trial_period", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "trial_period", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["trial_period"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TrialConfigProperties::TrialPeriodUnit TrialPeriodUnit - { - get - { - if (!this.Properties.TryGetValue("trial_period_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "trial_period_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("trial_period_unit"); - } - set - { - this.Properties["trial_period_unit"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.TrialPeriod; - this.TrialPeriodUnit.Validate(); - } - - public TrialConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TrialConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TrialConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Plans/PlanProperties/TrialConfigProperties/TrialPeriodUnit.cs b/src/Orb/Models/Plans/PlanProperties/TrialConfigProperties/TrialPeriodUnit.cs deleted file mode 100644 index 3fcb7bfb..00000000 --- a/src/Orb/Models/Plans/PlanProperties/TrialConfigProperties/TrialPeriodUnit.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Plans.PlanProperties.TrialConfigProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class TrialPeriodUnit(string value) : Orb::IEnum -{ - public static readonly TrialPeriodUnit Days = new("days"); - - readonly string _value = value; - - public enum Value - { - Days, - } - - public Value Known() => - _value switch - { - "days" => Value.Days, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static TrialPeriodUnit FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Plans/PlanUpdateParams.cs b/src/Orb/Models/Plans/PlanUpdateParams.cs index 637bbf58..cdbd9384 100644 --- a/src/Orb/Models/Plans/PlanUpdateParams.cs +++ b/src/Orb/Models/Plans/PlanUpdateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Plans; @@ -11,13 +13,17 @@ namespace Orb.Models.Plans; /// This endpoint can be used to update the `external_plan_id`, and `metadata` of /// an existing plan. /// -/// Other fields on a plan are currently immutable. +/// Other fields on a plan are currently immutable. /// -public sealed record class PlanUpdateParams : Orb::ParamsBase +public sealed record class PlanUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string PlanID; + public string? PlanID { get; init; } /// /// An optional user-defined ID for this plan resource, used throughout the system @@ -26,19 +32,8 @@ public sealed record class PlanUpdateParams : Orb::ParamsBase /// public string? ExternalPlanID { - get - { - if (!this.BodyProperties.TryGetValue("external_plan_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_plan_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_plan_id"); } + init { JsonModel.Set(this._rawBodyData, "external_plan_id", value); } } /// @@ -46,43 +41,90 @@ public string? ExternalPlanID /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public PlanUpdateParams() { } + + public PlanUpdateParams(PlanUpdateParams planUpdateParams) + : base(planUpdateParams) + { + this._rawBodyData = [.. planUpdateParams._rawBodyData]; + } + + public PlanUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PlanUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PlanUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/{0}", this.PlanID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/plans/{0}", this.PlanID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Price.cs b/src/Orb/Models/Price.cs index c70602d8..8721095c 100644 --- a/src/Orb/Models/Price.cs +++ b/src/Orb/Models/Price.cs @@ -1,118 +1,36735 @@ -using Orb = Orb; -using PriceProperties = Orb.Models.PriceProperties; -using PriceVariants = Orb.Models.PriceVariants; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; namespace Orb.Models; /// /// The Price resource represents a price that can be billed on a subscription, resulting -/// in a charge on an invoice in the form of an invoice line item. Prices take a -/// quantity and determine an amount to bill. +/// in a charge on an invoice in the form of an invoice line item. Prices take a quantity +/// and determine an amount to bill. /// -/// Orb supports a few different pricing models out of the box. Each of these models -/// is serialized differently in a given Price object. The model_type field determines -/// the key for the configuration object that is present. +/// Orb supports a few different pricing models out of the box. Each of these +/// models is serialized differently in a given Price object. The model_type field +/// determines the key for the configuration object that is present. /// -/// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) +/// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) /// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price +[JsonConverter(typeof(PriceConverter))] +public record class Price { - internal Price() { } + public object? Value { get; } = null; - public static PriceVariants::Unit Create(PriceProperties::Unit value) => new(value); + JsonElement? _element = null; - public static PriceVariants::Package Create(PriceProperties::Package value) => new(value); + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } - public static PriceVariants::Matrix Create(PriceProperties::Matrix value) => new(value); + public string ID + { + get + { + return Match( + unit: (x) => x.ID, + tiered: (x) => x.ID, + bulk: (x) => x.ID, + bulkWithFilters: (x) => x.ID, + package: (x) => x.ID, + matrix: (x) => x.ID, + thresholdTotalAmount: (x) => x.ID, + tieredPackage: (x) => x.ID, + tieredWithMinimum: (x) => x.ID, + groupedTiered: (x) => x.ID, + tieredPackageWithMinimum: (x) => x.ID, + packageWithAllocation: (x) => x.ID, + unitWithPercent: (x) => x.ID, + matrixWithAllocation: (x) => x.ID, + tieredWithProration: (x) => x.ID, + unitWithProration: (x) => x.ID, + groupedAllocation: (x) => x.ID, + bulkWithProration: (x) => x.ID, + groupedWithProratedMinimum: (x) => x.ID, + groupedWithMeteredMinimum: (x) => x.ID, + groupedWithMinMaxThresholds: (x) => x.ID, + matrixWithDisplayName: (x) => x.ID, + groupedTieredPackage: (x) => x.ID, + maxGroupTieredPackage: (x) => x.ID, + scalableMatrixWithUnitPricing: (x) => x.ID, + scalableMatrixWithTieredPricing: (x) => x.ID, + cumulativeGroupedBulk: (x) => x.ID, + cumulativeGroupedAllocation: (x) => x.ID, + minimum: (x) => x.ID, + percent: (x) => x.ID, + eventOutput: (x) => x.ID + ); + } + } - public static PriceVariants::Tiered Create(PriceProperties::Tiered value) => new(value); + public BillableMetricTiny? BillableMetric + { + get + { + return Match( + unit: (x) => x.BillableMetric, + tiered: (x) => x.BillableMetric, + bulk: (x) => x.BillableMetric, + bulkWithFilters: (x) => x.BillableMetric, + package: (x) => x.BillableMetric, + matrix: (x) => x.BillableMetric, + thresholdTotalAmount: (x) => x.BillableMetric, + tieredPackage: (x) => x.BillableMetric, + tieredWithMinimum: (x) => x.BillableMetric, + groupedTiered: (x) => x.BillableMetric, + tieredPackageWithMinimum: (x) => x.BillableMetric, + packageWithAllocation: (x) => x.BillableMetric, + unitWithPercent: (x) => x.BillableMetric, + matrixWithAllocation: (x) => x.BillableMetric, + tieredWithProration: (x) => x.BillableMetric, + unitWithProration: (x) => x.BillableMetric, + groupedAllocation: (x) => x.BillableMetric, + bulkWithProration: (x) => x.BillableMetric, + groupedWithProratedMinimum: (x) => x.BillableMetric, + groupedWithMeteredMinimum: (x) => x.BillableMetric, + groupedWithMinMaxThresholds: (x) => x.BillableMetric, + matrixWithDisplayName: (x) => x.BillableMetric, + groupedTieredPackage: (x) => x.BillableMetric, + maxGroupTieredPackage: (x) => x.BillableMetric, + scalableMatrixWithUnitPricing: (x) => x.BillableMetric, + scalableMatrixWithTieredPricing: (x) => x.BillableMetric, + cumulativeGroupedBulk: (x) => x.BillableMetric, + cumulativeGroupedAllocation: (x) => x.BillableMetric, + minimum: (x) => x.BillableMetric, + percent: (x) => x.BillableMetric, + eventOutput: (x) => x.BillableMetric + ); + } + } - public static PriceVariants::TieredBPS Create(PriceProperties::TieredBPS value) => new(value); + public BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return Match( + unit: (x) => x.BillingCycleConfiguration, + tiered: (x) => x.BillingCycleConfiguration, + bulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + package: (x) => x.BillingCycleConfiguration, + matrix: (x) => x.BillingCycleConfiguration, + thresholdTotalAmount: (x) => x.BillingCycleConfiguration, + tieredPackage: (x) => x.BillingCycleConfiguration, + tieredWithMinimum: (x) => x.BillingCycleConfiguration, + groupedTiered: (x) => x.BillingCycleConfiguration, + tieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + packageWithAllocation: (x) => x.BillingCycleConfiguration, + unitWithPercent: (x) => x.BillingCycleConfiguration, + matrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + unitWithProration: (x) => x.BillingCycleConfiguration, + groupedAllocation: (x) => x.BillingCycleConfiguration, + bulkWithProration: (x) => x.BillingCycleConfiguration, + groupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + matrixWithDisplayName: (x) => x.BillingCycleConfiguration, + groupedTieredPackage: (x) => x.BillingCycleConfiguration, + maxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + scalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + scalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + cumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + minimum: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } - public static PriceVariants::BPS Create(PriceProperties::BPS value) => new(value); + public double? ConversionRate + { + get + { + return Match( + unit: (x) => x.ConversionRate, + tiered: (x) => x.ConversionRate, + bulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + package: (x) => x.ConversionRate, + matrix: (x) => x.ConversionRate, + thresholdTotalAmount: (x) => x.ConversionRate, + tieredPackage: (x) => x.ConversionRate, + tieredWithMinimum: (x) => x.ConversionRate, + groupedTiered: (x) => x.ConversionRate, + tieredPackageWithMinimum: (x) => x.ConversionRate, + packageWithAllocation: (x) => x.ConversionRate, + unitWithPercent: (x) => x.ConversionRate, + matrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + unitWithProration: (x) => x.ConversionRate, + groupedAllocation: (x) => x.ConversionRate, + bulkWithProration: (x) => x.ConversionRate, + groupedWithProratedMinimum: (x) => x.ConversionRate, + groupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + matrixWithDisplayName: (x) => x.ConversionRate, + groupedTieredPackage: (x) => x.ConversionRate, + maxGroupTieredPackage: (x) => x.ConversionRate, + scalableMatrixWithUnitPricing: (x) => x.ConversionRate, + scalableMatrixWithTieredPricing: (x) => x.ConversionRate, + cumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + minimum: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } - public static PriceVariants::BulkBPS Create(PriceProperties::BulkBPS value) => new(value); + public System::DateTimeOffset CreatedAt + { + get + { + return Match( + unit: (x) => x.CreatedAt, + tiered: (x) => x.CreatedAt, + bulk: (x) => x.CreatedAt, + bulkWithFilters: (x) => x.CreatedAt, + package: (x) => x.CreatedAt, + matrix: (x) => x.CreatedAt, + thresholdTotalAmount: (x) => x.CreatedAt, + tieredPackage: (x) => x.CreatedAt, + tieredWithMinimum: (x) => x.CreatedAt, + groupedTiered: (x) => x.CreatedAt, + tieredPackageWithMinimum: (x) => x.CreatedAt, + packageWithAllocation: (x) => x.CreatedAt, + unitWithPercent: (x) => x.CreatedAt, + matrixWithAllocation: (x) => x.CreatedAt, + tieredWithProration: (x) => x.CreatedAt, + unitWithProration: (x) => x.CreatedAt, + groupedAllocation: (x) => x.CreatedAt, + bulkWithProration: (x) => x.CreatedAt, + groupedWithProratedMinimum: (x) => x.CreatedAt, + groupedWithMeteredMinimum: (x) => x.CreatedAt, + groupedWithMinMaxThresholds: (x) => x.CreatedAt, + matrixWithDisplayName: (x) => x.CreatedAt, + groupedTieredPackage: (x) => x.CreatedAt, + maxGroupTieredPackage: (x) => x.CreatedAt, + scalableMatrixWithUnitPricing: (x) => x.CreatedAt, + scalableMatrixWithTieredPricing: (x) => x.CreatedAt, + cumulativeGroupedBulk: (x) => x.CreatedAt, + cumulativeGroupedAllocation: (x) => x.CreatedAt, + minimum: (x) => x.CreatedAt, + percent: (x) => x.CreatedAt, + eventOutput: (x) => x.CreatedAt + ); + } + } - public static PriceVariants::Bulk Create(PriceProperties::Bulk value) => new(value); + public Allocation? CreditAllocation + { + get + { + return Match( + unit: (x) => x.CreditAllocation, + tiered: (x) => x.CreditAllocation, + bulk: (x) => x.CreditAllocation, + bulkWithFilters: (x) => x.CreditAllocation, + package: (x) => x.CreditAllocation, + matrix: (x) => x.CreditAllocation, + thresholdTotalAmount: (x) => x.CreditAllocation, + tieredPackage: (x) => x.CreditAllocation, + tieredWithMinimum: (x) => x.CreditAllocation, + groupedTiered: (x) => x.CreditAllocation, + tieredPackageWithMinimum: (x) => x.CreditAllocation, + packageWithAllocation: (x) => x.CreditAllocation, + unitWithPercent: (x) => x.CreditAllocation, + matrixWithAllocation: (x) => x.CreditAllocation, + tieredWithProration: (x) => x.CreditAllocation, + unitWithProration: (x) => x.CreditAllocation, + groupedAllocation: (x) => x.CreditAllocation, + bulkWithProration: (x) => x.CreditAllocation, + groupedWithProratedMinimum: (x) => x.CreditAllocation, + groupedWithMeteredMinimum: (x) => x.CreditAllocation, + groupedWithMinMaxThresholds: (x) => x.CreditAllocation, + matrixWithDisplayName: (x) => x.CreditAllocation, + groupedTieredPackage: (x) => x.CreditAllocation, + maxGroupTieredPackage: (x) => x.CreditAllocation, + scalableMatrixWithUnitPricing: (x) => x.CreditAllocation, + scalableMatrixWithTieredPricing: (x) => x.CreditAllocation, + cumulativeGroupedBulk: (x) => x.CreditAllocation, + cumulativeGroupedAllocation: (x) => x.CreditAllocation, + minimum: (x) => x.CreditAllocation, + percent: (x) => x.CreditAllocation, + eventOutput: (x) => x.CreditAllocation + ); + } + } - public static PriceVariants::ThresholdTotalAmount Create( - PriceProperties::ThresholdTotalAmount value + public string Currency + { + get + { + return Match( + unit: (x) => x.Currency, + tiered: (x) => x.Currency, + bulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + package: (x) => x.Currency, + matrix: (x) => x.Currency, + thresholdTotalAmount: (x) => x.Currency, + tieredPackage: (x) => x.Currency, + tieredWithMinimum: (x) => x.Currency, + groupedTiered: (x) => x.Currency, + tieredPackageWithMinimum: (x) => x.Currency, + packageWithAllocation: (x) => x.Currency, + unitWithPercent: (x) => x.Currency, + matrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + unitWithProration: (x) => x.Currency, + groupedAllocation: (x) => x.Currency, + bulkWithProration: (x) => x.Currency, + groupedWithProratedMinimum: (x) => x.Currency, + groupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + matrixWithDisplayName: (x) => x.Currency, + groupedTieredPackage: (x) => x.Currency, + maxGroupTieredPackage: (x) => x.Currency, + scalableMatrixWithUnitPricing: (x) => x.Currency, + scalableMatrixWithTieredPricing: (x) => x.Currency, + cumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + minimum: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public SharedDiscount? Discount + { + get + { + return Match( + unit: (x) => x.Discount, + tiered: (x) => x.Discount, + bulk: (x) => x.Discount, + bulkWithFilters: (x) => x.Discount, + package: (x) => x.Discount, + matrix: (x) => x.Discount, + thresholdTotalAmount: (x) => x.Discount, + tieredPackage: (x) => x.Discount, + tieredWithMinimum: (x) => x.Discount, + groupedTiered: (x) => x.Discount, + tieredPackageWithMinimum: (x) => x.Discount, + packageWithAllocation: (x) => x.Discount, + unitWithPercent: (x) => x.Discount, + matrixWithAllocation: (x) => x.Discount, + tieredWithProration: (x) => x.Discount, + unitWithProration: (x) => x.Discount, + groupedAllocation: (x) => x.Discount, + bulkWithProration: (x) => x.Discount, + groupedWithProratedMinimum: (x) => x.Discount, + groupedWithMeteredMinimum: (x) => x.Discount, + groupedWithMinMaxThresholds: (x) => x.Discount, + matrixWithDisplayName: (x) => x.Discount, + groupedTieredPackage: (x) => x.Discount, + maxGroupTieredPackage: (x) => x.Discount, + scalableMatrixWithUnitPricing: (x) => x.Discount, + scalableMatrixWithTieredPricing: (x) => x.Discount, + cumulativeGroupedBulk: (x) => x.Discount, + cumulativeGroupedAllocation: (x) => x.Discount, + minimum: (x) => x.Discount, + percent: (x) => x.Discount, + eventOutput: (x) => x.Discount + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + unit: (x) => x.ExternalPriceID, + tiered: (x) => x.ExternalPriceID, + bulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + package: (x) => x.ExternalPriceID, + matrix: (x) => x.ExternalPriceID, + thresholdTotalAmount: (x) => x.ExternalPriceID, + tieredPackage: (x) => x.ExternalPriceID, + tieredWithMinimum: (x) => x.ExternalPriceID, + groupedTiered: (x) => x.ExternalPriceID, + tieredPackageWithMinimum: (x) => x.ExternalPriceID, + packageWithAllocation: (x) => x.ExternalPriceID, + unitWithPercent: (x) => x.ExternalPriceID, + matrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + unitWithProration: (x) => x.ExternalPriceID, + groupedAllocation: (x) => x.ExternalPriceID, + bulkWithProration: (x) => x.ExternalPriceID, + groupedWithProratedMinimum: (x) => x.ExternalPriceID, + groupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + matrixWithDisplayName: (x) => x.ExternalPriceID, + groupedTieredPackage: (x) => x.ExternalPriceID, + maxGroupTieredPackage: (x) => x.ExternalPriceID, + scalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + scalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + cumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + minimum: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + unit: (x) => x.FixedPriceQuantity, + tiered: (x) => x.FixedPriceQuantity, + bulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + package: (x) => x.FixedPriceQuantity, + matrix: (x) => x.FixedPriceQuantity, + thresholdTotalAmount: (x) => x.FixedPriceQuantity, + tieredPackage: (x) => x.FixedPriceQuantity, + tieredWithMinimum: (x) => x.FixedPriceQuantity, + groupedTiered: (x) => x.FixedPriceQuantity, + tieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + packageWithAllocation: (x) => x.FixedPriceQuantity, + unitWithPercent: (x) => x.FixedPriceQuantity, + matrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + unitWithProration: (x) => x.FixedPriceQuantity, + groupedAllocation: (x) => x.FixedPriceQuantity, + bulkWithProration: (x) => x.FixedPriceQuantity, + groupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + groupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + matrixWithDisplayName: (x) => x.FixedPriceQuantity, + groupedTieredPackage: (x) => x.FixedPriceQuantity, + maxGroupTieredPackage: (x) => x.FixedPriceQuantity, + scalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + scalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + cumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + minimum: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + unit: (x) => x.InvoicingCycleConfiguration, + tiered: (x) => x.InvoicingCycleConfiguration, + bulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + package: (x) => x.InvoicingCycleConfiguration, + matrix: (x) => x.InvoicingCycleConfiguration, + thresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + tieredPackage: (x) => x.InvoicingCycleConfiguration, + tieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + groupedTiered: (x) => x.InvoicingCycleConfiguration, + tieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + packageWithAllocation: (x) => x.InvoicingCycleConfiguration, + unitWithPercent: (x) => x.InvoicingCycleConfiguration, + matrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + unitWithProration: (x) => x.InvoicingCycleConfiguration, + groupedAllocation: (x) => x.InvoicingCycleConfiguration, + bulkWithProration: (x) => x.InvoicingCycleConfiguration, + groupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + matrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + groupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + maxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + scalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + scalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + minimum: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public ItemSlim Item + { + get + { + return Match( + unit: (x) => x.Item, + tiered: (x) => x.Item, + bulk: (x) => x.Item, + bulkWithFilters: (x) => x.Item, + package: (x) => x.Item, + matrix: (x) => x.Item, + thresholdTotalAmount: (x) => x.Item, + tieredPackage: (x) => x.Item, + tieredWithMinimum: (x) => x.Item, + groupedTiered: (x) => x.Item, + tieredPackageWithMinimum: (x) => x.Item, + packageWithAllocation: (x) => x.Item, + unitWithPercent: (x) => x.Item, + matrixWithAllocation: (x) => x.Item, + tieredWithProration: (x) => x.Item, + unitWithProration: (x) => x.Item, + groupedAllocation: (x) => x.Item, + bulkWithProration: (x) => x.Item, + groupedWithProratedMinimum: (x) => x.Item, + groupedWithMeteredMinimum: (x) => x.Item, + groupedWithMinMaxThresholds: (x) => x.Item, + matrixWithDisplayName: (x) => x.Item, + groupedTieredPackage: (x) => x.Item, + maxGroupTieredPackage: (x) => x.Item, + scalableMatrixWithUnitPricing: (x) => x.Item, + scalableMatrixWithTieredPricing: (x) => x.Item, + cumulativeGroupedBulk: (x) => x.Item, + cumulativeGroupedAllocation: (x) => x.Item, + minimum: (x) => x.Item, + percent: (x) => x.Item, + eventOutput: (x) => x.Item + ); + } + } + + public Maximum? Maximum + { + get + { + return Match( + unit: (x) => x.Maximum, + tiered: (x) => x.Maximum, + bulk: (x) => x.Maximum, + bulkWithFilters: (x) => x.Maximum, + package: (x) => x.Maximum, + matrix: (x) => x.Maximum, + thresholdTotalAmount: (x) => x.Maximum, + tieredPackage: (x) => x.Maximum, + tieredWithMinimum: (x) => x.Maximum, + groupedTiered: (x) => x.Maximum, + tieredPackageWithMinimum: (x) => x.Maximum, + packageWithAllocation: (x) => x.Maximum, + unitWithPercent: (x) => x.Maximum, + matrixWithAllocation: (x) => x.Maximum, + tieredWithProration: (x) => x.Maximum, + unitWithProration: (x) => x.Maximum, + groupedAllocation: (x) => x.Maximum, + bulkWithProration: (x) => x.Maximum, + groupedWithProratedMinimum: (x) => x.Maximum, + groupedWithMeteredMinimum: (x) => x.Maximum, + groupedWithMinMaxThresholds: (x) => x.Maximum, + matrixWithDisplayName: (x) => x.Maximum, + groupedTieredPackage: (x) => x.Maximum, + maxGroupTieredPackage: (x) => x.Maximum, + scalableMatrixWithUnitPricing: (x) => x.Maximum, + scalableMatrixWithTieredPricing: (x) => x.Maximum, + cumulativeGroupedBulk: (x) => x.Maximum, + cumulativeGroupedAllocation: (x) => x.Maximum, + minimum: (x) => x.Maximum, + percent: (x) => x.Maximum, + eventOutput: (x) => x.Maximum + ); + } + } + + public string? MaximumAmount + { + get + { + return Match( + unit: (x) => x.MaximumAmount, + tiered: (x) => x.MaximumAmount, + bulk: (x) => x.MaximumAmount, + bulkWithFilters: (x) => x.MaximumAmount, + package: (x) => x.MaximumAmount, + matrix: (x) => x.MaximumAmount, + thresholdTotalAmount: (x) => x.MaximumAmount, + tieredPackage: (x) => x.MaximumAmount, + tieredWithMinimum: (x) => x.MaximumAmount, + groupedTiered: (x) => x.MaximumAmount, + tieredPackageWithMinimum: (x) => x.MaximumAmount, + packageWithAllocation: (x) => x.MaximumAmount, + unitWithPercent: (x) => x.MaximumAmount, + matrixWithAllocation: (x) => x.MaximumAmount, + tieredWithProration: (x) => x.MaximumAmount, + unitWithProration: (x) => x.MaximumAmount, + groupedAllocation: (x) => x.MaximumAmount, + bulkWithProration: (x) => x.MaximumAmount, + groupedWithProratedMinimum: (x) => x.MaximumAmount, + groupedWithMeteredMinimum: (x) => x.MaximumAmount, + groupedWithMinMaxThresholds: (x) => x.MaximumAmount, + matrixWithDisplayName: (x) => x.MaximumAmount, + groupedTieredPackage: (x) => x.MaximumAmount, + maxGroupTieredPackage: (x) => x.MaximumAmount, + scalableMatrixWithUnitPricing: (x) => x.MaximumAmount, + scalableMatrixWithTieredPricing: (x) => x.MaximumAmount, + cumulativeGroupedBulk: (x) => x.MaximumAmount, + cumulativeGroupedAllocation: (x) => x.MaximumAmount, + minimum: (x) => x.MaximumAmount, + percent: (x) => x.MaximumAmount, + eventOutput: (x) => x.MaximumAmount + ); + } + } + + public Minimum? Minimum + { + get + { + return Match( + unit: (x) => x.Minimum, + tiered: (x) => x.Minimum, + bulk: (x) => x.Minimum, + bulkWithFilters: (x) => x.Minimum, + package: (x) => x.Minimum, + matrix: (x) => x.Minimum, + thresholdTotalAmount: (x) => x.Minimum, + tieredPackage: (x) => x.Minimum, + tieredWithMinimum: (x) => x.Minimum, + groupedTiered: (x) => x.Minimum, + tieredPackageWithMinimum: (x) => x.Minimum, + packageWithAllocation: (x) => x.Minimum, + unitWithPercent: (x) => x.Minimum, + matrixWithAllocation: (x) => x.Minimum, + tieredWithProration: (x) => x.Minimum, + unitWithProration: (x) => x.Minimum, + groupedAllocation: (x) => x.Minimum, + bulkWithProration: (x) => x.Minimum, + groupedWithProratedMinimum: (x) => x.Minimum, + groupedWithMeteredMinimum: (x) => x.Minimum, + groupedWithMinMaxThresholds: (x) => x.Minimum, + matrixWithDisplayName: (x) => x.Minimum, + groupedTieredPackage: (x) => x.Minimum, + maxGroupTieredPackage: (x) => x.Minimum, + scalableMatrixWithUnitPricing: (x) => x.Minimum, + scalableMatrixWithTieredPricing: (x) => x.Minimum, + cumulativeGroupedBulk: (x) => x.Minimum, + cumulativeGroupedAllocation: (x) => x.Minimum, + minimum: (x) => x.Minimum, + percent: (x) => x.Minimum, + eventOutput: (x) => x.Minimum + ); + } + } + + public string? MinimumAmount + { + get + { + return Match( + unit: (x) => x.MinimumAmount, + tiered: (x) => x.MinimumAmount, + bulk: (x) => x.MinimumAmount, + bulkWithFilters: (x) => x.MinimumAmount, + package: (x) => x.MinimumAmount, + matrix: (x) => x.MinimumAmount, + thresholdTotalAmount: (x) => x.MinimumAmount, + tieredPackage: (x) => x.MinimumAmount, + tieredWithMinimum: (x) => x.MinimumAmount, + groupedTiered: (x) => x.MinimumAmount, + tieredPackageWithMinimum: (x) => x.MinimumAmount, + packageWithAllocation: (x) => x.MinimumAmount, + unitWithPercent: (x) => x.MinimumAmount, + matrixWithAllocation: (x) => x.MinimumAmount, + tieredWithProration: (x) => x.MinimumAmount, + unitWithProration: (x) => x.MinimumAmount, + groupedAllocation: (x) => x.MinimumAmount, + bulkWithProration: (x) => x.MinimumAmount, + groupedWithProratedMinimum: (x) => x.MinimumAmount, + groupedWithMeteredMinimum: (x) => x.MinimumAmount, + groupedWithMinMaxThresholds: (x) => x.MinimumAmount, + matrixWithDisplayName: (x) => x.MinimumAmount, + groupedTieredPackage: (x) => x.MinimumAmount, + maxGroupTieredPackage: (x) => x.MinimumAmount, + scalableMatrixWithUnitPricing: (x) => x.MinimumAmount, + scalableMatrixWithTieredPricing: (x) => x.MinimumAmount, + cumulativeGroupedBulk: (x) => x.MinimumAmount, + cumulativeGroupedAllocation: (x) => x.MinimumAmount, + minimum: (x) => x.MinimumAmount, + percent: (x) => x.MinimumAmount, + eventOutput: (x) => x.MinimumAmount + ); + } + } + + public JsonElement ModelType + { + get + { + return Match( + unit: (x) => x.ModelType, + tiered: (x) => x.ModelType, + bulk: (x) => x.ModelType, + bulkWithFilters: (x) => x.ModelType, + package: (x) => x.ModelType, + matrix: (x) => x.ModelType, + thresholdTotalAmount: (x) => x.ModelType, + tieredPackage: (x) => x.ModelType, + tieredWithMinimum: (x) => x.ModelType, + groupedTiered: (x) => x.ModelType, + tieredPackageWithMinimum: (x) => x.ModelType, + packageWithAllocation: (x) => x.ModelType, + unitWithPercent: (x) => x.ModelType, + matrixWithAllocation: (x) => x.ModelType, + tieredWithProration: (x) => x.ModelType, + unitWithProration: (x) => x.ModelType, + groupedAllocation: (x) => x.ModelType, + bulkWithProration: (x) => x.ModelType, + groupedWithProratedMinimum: (x) => x.ModelType, + groupedWithMeteredMinimum: (x) => x.ModelType, + groupedWithMinMaxThresholds: (x) => x.ModelType, + matrixWithDisplayName: (x) => x.ModelType, + groupedTieredPackage: (x) => x.ModelType, + maxGroupTieredPackage: (x) => x.ModelType, + scalableMatrixWithUnitPricing: (x) => x.ModelType, + scalableMatrixWithTieredPricing: (x) => x.ModelType, + cumulativeGroupedBulk: (x) => x.ModelType, + cumulativeGroupedAllocation: (x) => x.ModelType, + minimum: (x) => x.ModelType, + percent: (x) => x.ModelType, + eventOutput: (x) => x.ModelType + ); + } + } + + public string Name + { + get + { + return Match( + unit: (x) => x.Name, + tiered: (x) => x.Name, + bulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + package: (x) => x.Name, + matrix: (x) => x.Name, + thresholdTotalAmount: (x) => x.Name, + tieredPackage: (x) => x.Name, + tieredWithMinimum: (x) => x.Name, + groupedTiered: (x) => x.Name, + tieredPackageWithMinimum: (x) => x.Name, + packageWithAllocation: (x) => x.Name, + unitWithPercent: (x) => x.Name, + matrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + unitWithProration: (x) => x.Name, + groupedAllocation: (x) => x.Name, + bulkWithProration: (x) => x.Name, + groupedWithProratedMinimum: (x) => x.Name, + groupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + matrixWithDisplayName: (x) => x.Name, + groupedTieredPackage: (x) => x.Name, + maxGroupTieredPackage: (x) => x.Name, + scalableMatrixWithUnitPricing: (x) => x.Name, + scalableMatrixWithTieredPricing: (x) => x.Name, + cumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + minimum: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public long? PlanPhaseOrder + { + get + { + return Match( + unit: (x) => x.PlanPhaseOrder, + tiered: (x) => x.PlanPhaseOrder, + bulk: (x) => x.PlanPhaseOrder, + bulkWithFilters: (x) => x.PlanPhaseOrder, + package: (x) => x.PlanPhaseOrder, + matrix: (x) => x.PlanPhaseOrder, + thresholdTotalAmount: (x) => x.PlanPhaseOrder, + tieredPackage: (x) => x.PlanPhaseOrder, + tieredWithMinimum: (x) => x.PlanPhaseOrder, + groupedTiered: (x) => x.PlanPhaseOrder, + tieredPackageWithMinimum: (x) => x.PlanPhaseOrder, + packageWithAllocation: (x) => x.PlanPhaseOrder, + unitWithPercent: (x) => x.PlanPhaseOrder, + matrixWithAllocation: (x) => x.PlanPhaseOrder, + tieredWithProration: (x) => x.PlanPhaseOrder, + unitWithProration: (x) => x.PlanPhaseOrder, + groupedAllocation: (x) => x.PlanPhaseOrder, + bulkWithProration: (x) => x.PlanPhaseOrder, + groupedWithProratedMinimum: (x) => x.PlanPhaseOrder, + groupedWithMeteredMinimum: (x) => x.PlanPhaseOrder, + groupedWithMinMaxThresholds: (x) => x.PlanPhaseOrder, + matrixWithDisplayName: (x) => x.PlanPhaseOrder, + groupedTieredPackage: (x) => x.PlanPhaseOrder, + maxGroupTieredPackage: (x) => x.PlanPhaseOrder, + scalableMatrixWithUnitPricing: (x) => x.PlanPhaseOrder, + scalableMatrixWithTieredPricing: (x) => x.PlanPhaseOrder, + cumulativeGroupedBulk: (x) => x.PlanPhaseOrder, + cumulativeGroupedAllocation: (x) => x.PlanPhaseOrder, + minimum: (x) => x.PlanPhaseOrder, + percent: (x) => x.PlanPhaseOrder, + eventOutput: (x) => x.PlanPhaseOrder + ); + } + } + + public string? ReplacesPriceID + { + get + { + return Match( + unit: (x) => x.ReplacesPriceID, + tiered: (x) => x.ReplacesPriceID, + bulk: (x) => x.ReplacesPriceID, + bulkWithFilters: (x) => x.ReplacesPriceID, + package: (x) => x.ReplacesPriceID, + matrix: (x) => x.ReplacesPriceID, + thresholdTotalAmount: (x) => x.ReplacesPriceID, + tieredPackage: (x) => x.ReplacesPriceID, + tieredWithMinimum: (x) => x.ReplacesPriceID, + groupedTiered: (x) => x.ReplacesPriceID, + tieredPackageWithMinimum: (x) => x.ReplacesPriceID, + packageWithAllocation: (x) => x.ReplacesPriceID, + unitWithPercent: (x) => x.ReplacesPriceID, + matrixWithAllocation: (x) => x.ReplacesPriceID, + tieredWithProration: (x) => x.ReplacesPriceID, + unitWithProration: (x) => x.ReplacesPriceID, + groupedAllocation: (x) => x.ReplacesPriceID, + bulkWithProration: (x) => x.ReplacesPriceID, + groupedWithProratedMinimum: (x) => x.ReplacesPriceID, + groupedWithMeteredMinimum: (x) => x.ReplacesPriceID, + groupedWithMinMaxThresholds: (x) => x.ReplacesPriceID, + matrixWithDisplayName: (x) => x.ReplacesPriceID, + groupedTieredPackage: (x) => x.ReplacesPriceID, + maxGroupTieredPackage: (x) => x.ReplacesPriceID, + scalableMatrixWithUnitPricing: (x) => x.ReplacesPriceID, + scalableMatrixWithTieredPricing: (x) => x.ReplacesPriceID, + cumulativeGroupedBulk: (x) => x.ReplacesPriceID, + cumulativeGroupedAllocation: (x) => x.ReplacesPriceID, + minimum: (x) => x.ReplacesPriceID, + percent: (x) => x.ReplacesPriceID, + eventOutput: (x) => x.ReplacesPriceID + ); + } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + unit: (x) => x.DimensionalPriceConfiguration, + tiered: (x) => x.DimensionalPriceConfiguration, + bulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + package: (x) => x.DimensionalPriceConfiguration, + matrix: (x) => x.DimensionalPriceConfiguration, + thresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + tieredPackage: (x) => x.DimensionalPriceConfiguration, + tieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + groupedTiered: (x) => x.DimensionalPriceConfiguration, + tieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + packageWithAllocation: (x) => x.DimensionalPriceConfiguration, + unitWithPercent: (x) => x.DimensionalPriceConfiguration, + matrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + unitWithProration: (x) => x.DimensionalPriceConfiguration, + groupedAllocation: (x) => x.DimensionalPriceConfiguration, + bulkWithProration: (x) => x.DimensionalPriceConfiguration, + groupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + matrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + groupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + maxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + scalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + scalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + minimum: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public Price(Unit value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(Tiered value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(Bulk value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(BulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(Package value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(Matrix value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(ThresholdTotalAmount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(TieredPackage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(TieredWithMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(GroupedTiered value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(TieredPackageWithMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PackageWithAllocation value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(UnitWithPercent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(MatrixWithAllocation value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(TieredWithProration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(UnitWithProration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(GroupedAllocation value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(BulkWithProration value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(GroupedWithProratedMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(GroupedWithMeteredMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(GroupedWithMinMaxThresholds value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(MatrixWithDisplayName value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(GroupedTieredPackage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(MaxGroupTieredPackage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(ScalableMatrixWithUnitPricing value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(ScalableMatrixWithTieredPricing value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(CumulativeGroupedBulk value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(CumulativeGroupedAllocation value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PriceMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(Percent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(EventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `Unit` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out Unit? value) + { + value = this.Value as Unit; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `Tiered` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out Tiered? value) + { + value = this.Value as Tiered; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulk(out var value)) { + /// // `value` is of type `Bulk` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulk([NotNullWhen(true)] out Bulk? value) + { + value = this.Value as Bulk; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `BulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters([NotNullWhen(true)] out BulkWithFilters? value) + { + value = this.Value as BulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPackage(out var value)) { + /// // `value` is of type `Package` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPackage([NotNullWhen(true)] out Package? value) + { + value = this.Value as Package; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrix(out var value)) { + /// // `value` is of type `Matrix` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrix([NotNullWhen(true)] out Matrix? value) + { + value = this.Value as Matrix; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickThresholdTotalAmount(out var value)) { + /// // `value` is of type `ThresholdTotalAmount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickThresholdTotalAmount([NotNullWhen(true)] out ThresholdTotalAmount? value) + { + value = this.Value as ThresholdTotalAmount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredPackage(out var value)) { + /// // `value` is of type `TieredPackage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredPackage([NotNullWhen(true)] out TieredPackage? value) + { + value = this.Value as TieredPackage; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithMinimum(out var value)) { + /// // `value` is of type `TieredWithMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithMinimum([NotNullWhen(true)] out TieredWithMinimum? value) + { + value = this.Value as TieredWithMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedTiered(out var value)) { + /// // `value` is of type `GroupedTiered` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedTiered([NotNullWhen(true)] out GroupedTiered? value) + { + value = this.Value as GroupedTiered; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `TieredPackageWithMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredPackageWithMinimum( + [NotNullWhen(true)] out TieredPackageWithMinimum? value + ) + { + value = this.Value as TieredPackageWithMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPackageWithAllocation(out var value)) { + /// // `value` is of type `PackageWithAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPackageWithAllocation([NotNullWhen(true)] out PackageWithAllocation? value) + { + value = this.Value as PackageWithAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnitWithPercent(out var value)) { + /// // `value` is of type `UnitWithPercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnitWithPercent([NotNullWhen(true)] out UnitWithPercent? value) + { + value = this.Value as UnitWithPercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrixWithAllocation(out var value)) { + /// // `value` is of type `MatrixWithAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrixWithAllocation([NotNullWhen(true)] out MatrixWithAllocation? value) + { + value = this.Value as MatrixWithAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `TieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration([NotNullWhen(true)] out TieredWithProration? value) + { + value = this.Value as TieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnitWithProration(out var value)) { + /// // `value` is of type `UnitWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnitWithProration([NotNullWhen(true)] out UnitWithProration? value) + { + value = this.Value as UnitWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedAllocation(out var value)) { + /// // `value` is of type `GroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedAllocation([NotNullWhen(true)] out GroupedAllocation? value) + { + value = this.Value as GroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithProration(out var value)) { + /// // `value` is of type `BulkWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithProration([NotNullWhen(true)] out BulkWithProration? value) + { + value = this.Value as BulkWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `GroupedWithProratedMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithProratedMinimum( + [NotNullWhen(true)] out GroupedWithProratedMinimum? value + ) + { + value = this.Value as GroupedWithProratedMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `GroupedWithMeteredMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMeteredMinimum( + [NotNullWhen(true)] out GroupedWithMeteredMinimum? value + ) + { + value = this.Value as GroupedWithMeteredMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `GroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out GroupedWithMinMaxThresholds? value + ) + { + value = this.Value as GroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMatrixWithDisplayName(out var value)) { + /// // `value` is of type `MatrixWithDisplayName` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMatrixWithDisplayName([NotNullWhen(true)] out MatrixWithDisplayName? value) + { + value = this.Value as MatrixWithDisplayName; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedTieredPackage(out var value)) { + /// // `value` is of type `GroupedTieredPackage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedTieredPackage([NotNullWhen(true)] out GroupedTieredPackage? value) + { + value = this.Value as GroupedTieredPackage; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `MaxGroupTieredPackage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMaxGroupTieredPackage([NotNullWhen(true)] out MaxGroupTieredPackage? value) + { + value = this.Value as MaxGroupTieredPackage; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `ScalableMatrixWithUnitPricing` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out ScalableMatrixWithUnitPricing? value + ) + { + value = this.Value as ScalableMatrixWithUnitPricing; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `ScalableMatrixWithTieredPricing` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out ScalableMatrixWithTieredPricing? value + ) + { + value = this.Value as ScalableMatrixWithTieredPricing; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `CumulativeGroupedBulk` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedBulk([NotNullWhen(true)] out CumulativeGroupedBulk? value) + { + value = this.Value as CumulativeGroupedBulk; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `CumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out CumulativeGroupedAllocation? value + ) + { + value = this.Value as CumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickMinimum(out var value)) { + /// // `value` is of type `PriceMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickMinimum([NotNullWhen(true)] out PriceMinimum? value) + { + value = this.Value as PriceMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `Percent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out Percent? value) + { + value = this.Value as Percent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `EventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput([NotNullWhen(true)] out EventOutput? value) + { + value = this.Value as EventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (Unit value) => {...}, + /// (Tiered value) => {...}, + /// (Bulk value) => {...}, + /// (BulkWithFilters value) => {...}, + /// (Package value) => {...}, + /// (Matrix value) => {...}, + /// (ThresholdTotalAmount value) => {...}, + /// (TieredPackage value) => {...}, + /// (TieredWithMinimum value) => {...}, + /// (GroupedTiered value) => {...}, + /// (TieredPackageWithMinimum value) => {...}, + /// (PackageWithAllocation value) => {...}, + /// (UnitWithPercent value) => {...}, + /// (MatrixWithAllocation value) => {...}, + /// (TieredWithProration value) => {...}, + /// (UnitWithProration value) => {...}, + /// (GroupedAllocation value) => {...}, + /// (BulkWithProration value) => {...}, + /// (GroupedWithProratedMinimum value) => {...}, + /// (GroupedWithMeteredMinimum value) => {...}, + /// (GroupedWithMinMaxThresholds value) => {...}, + /// (MatrixWithDisplayName value) => {...}, + /// (GroupedTieredPackage value) => {...}, + /// (MaxGroupTieredPackage value) => {...}, + /// (ScalableMatrixWithUnitPricing value) => {...}, + /// (ScalableMatrixWithTieredPricing value) => {...}, + /// (CumulativeGroupedBulk value) => {...}, + /// (CumulativeGroupedAllocation value) => {...}, + /// (PriceMinimum value) => {...}, + /// (Percent value) => {...}, + /// (EventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered, + System::Action bulk, + System::Action bulkWithFilters, + System::Action package, + System::Action matrix, + System::Action thresholdTotalAmount, + System::Action tieredPackage, + System::Action tieredWithMinimum, + System::Action groupedTiered, + System::Action tieredPackageWithMinimum, + System::Action packageWithAllocation, + System::Action unitWithPercent, + System::Action matrixWithAllocation, + System::Action tieredWithProration, + System::Action unitWithProration, + System::Action groupedAllocation, + System::Action bulkWithProration, + System::Action groupedWithProratedMinimum, + System::Action groupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action matrixWithDisplayName, + System::Action groupedTieredPackage, + System::Action maxGroupTieredPackage, + System::Action scalableMatrixWithUnitPricing, + System::Action scalableMatrixWithTieredPricing, + System::Action cumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action minimum, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case Unit value: + unit(value); + break; + case Tiered value: + tiered(value); + break; + case Bulk value: + bulk(value); + break; + case BulkWithFilters value: + bulkWithFilters(value); + break; + case Package value: + package(value); + break; + case Matrix value: + matrix(value); + break; + case ThresholdTotalAmount value: + thresholdTotalAmount(value); + break; + case TieredPackage value: + tieredPackage(value); + break; + case TieredWithMinimum value: + tieredWithMinimum(value); + break; + case GroupedTiered value: + groupedTiered(value); + break; + case TieredPackageWithMinimum value: + tieredPackageWithMinimum(value); + break; + case PackageWithAllocation value: + packageWithAllocation(value); + break; + case UnitWithPercent value: + unitWithPercent(value); + break; + case MatrixWithAllocation value: + matrixWithAllocation(value); + break; + case TieredWithProration value: + tieredWithProration(value); + break; + case UnitWithProration value: + unitWithProration(value); + break; + case GroupedAllocation value: + groupedAllocation(value); + break; + case BulkWithProration value: + bulkWithProration(value); + break; + case GroupedWithProratedMinimum value: + groupedWithProratedMinimum(value); + break; + case GroupedWithMeteredMinimum value: + groupedWithMeteredMinimum(value); + break; + case GroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case MatrixWithDisplayName value: + matrixWithDisplayName(value); + break; + case GroupedTieredPackage value: + groupedTieredPackage(value); + break; + case MaxGroupTieredPackage value: + maxGroupTieredPackage(value); + break; + case ScalableMatrixWithUnitPricing value: + scalableMatrixWithUnitPricing(value); + break; + case ScalableMatrixWithTieredPricing value: + scalableMatrixWithTieredPricing(value); + break; + case CumulativeGroupedBulk value: + cumulativeGroupedBulk(value); + break; + case CumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case PriceMinimum value: + minimum(value); + break; + case Percent value: + percent(value); + break; + case EventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (Unit value) => {...}, + /// (Tiered value) => {...}, + /// (Bulk value) => {...}, + /// (BulkWithFilters value) => {...}, + /// (Package value) => {...}, + /// (Matrix value) => {...}, + /// (ThresholdTotalAmount value) => {...}, + /// (TieredPackage value) => {...}, + /// (TieredWithMinimum value) => {...}, + /// (GroupedTiered value) => {...}, + /// (TieredPackageWithMinimum value) => {...}, + /// (PackageWithAllocation value) => {...}, + /// (UnitWithPercent value) => {...}, + /// (MatrixWithAllocation value) => {...}, + /// (TieredWithProration value) => {...}, + /// (UnitWithProration value) => {...}, + /// (GroupedAllocation value) => {...}, + /// (BulkWithProration value) => {...}, + /// (GroupedWithProratedMinimum value) => {...}, + /// (GroupedWithMeteredMinimum value) => {...}, + /// (GroupedWithMinMaxThresholds value) => {...}, + /// (MatrixWithDisplayName value) => {...}, + /// (GroupedTieredPackage value) => {...}, + /// (MaxGroupTieredPackage value) => {...}, + /// (ScalableMatrixWithUnitPricing value) => {...}, + /// (ScalableMatrixWithTieredPricing value) => {...}, + /// (CumulativeGroupedBulk value) => {...}, + /// (CumulativeGroupedAllocation value) => {...}, + /// (PriceMinimum value) => {...}, + /// (Percent value) => {...}, + /// (EventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered, + System::Func bulk, + System::Func bulkWithFilters, + System::Func package, + System::Func matrix, + System::Func thresholdTotalAmount, + System::Func tieredPackage, + System::Func tieredWithMinimum, + System::Func groupedTiered, + System::Func tieredPackageWithMinimum, + System::Func packageWithAllocation, + System::Func unitWithPercent, + System::Func matrixWithAllocation, + System::Func tieredWithProration, + System::Func unitWithProration, + System::Func groupedAllocation, + System::Func bulkWithProration, + System::Func groupedWithProratedMinimum, + System::Func groupedWithMeteredMinimum, + System::Func groupedWithMinMaxThresholds, + System::Func matrixWithDisplayName, + System::Func groupedTieredPackage, + System::Func maxGroupTieredPackage, + System::Func scalableMatrixWithUnitPricing, + System::Func scalableMatrixWithTieredPricing, + System::Func cumulativeGroupedBulk, + System::Func cumulativeGroupedAllocation, + System::Func minimum, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + Unit value => unit(value), + Tiered value => tiered(value), + Bulk value => bulk(value), + BulkWithFilters value => bulkWithFilters(value), + Package value => package(value), + Matrix value => matrix(value), + ThresholdTotalAmount value => thresholdTotalAmount(value), + TieredPackage value => tieredPackage(value), + TieredWithMinimum value => tieredWithMinimum(value), + GroupedTiered value => groupedTiered(value), + TieredPackageWithMinimum value => tieredPackageWithMinimum(value), + PackageWithAllocation value => packageWithAllocation(value), + UnitWithPercent value => unitWithPercent(value), + MatrixWithAllocation value => matrixWithAllocation(value), + TieredWithProration value => tieredWithProration(value), + UnitWithProration value => unitWithProration(value), + GroupedAllocation value => groupedAllocation(value), + BulkWithProration value => bulkWithProration(value), + GroupedWithProratedMinimum value => groupedWithProratedMinimum(value), + GroupedWithMeteredMinimum value => groupedWithMeteredMinimum(value), + GroupedWithMinMaxThresholds value => groupedWithMinMaxThresholds(value), + MatrixWithDisplayName value => matrixWithDisplayName(value), + GroupedTieredPackage value => groupedTieredPackage(value), + MaxGroupTieredPackage value => maxGroupTieredPackage(value), + ScalableMatrixWithUnitPricing value => scalableMatrixWithUnitPricing(value), + ScalableMatrixWithTieredPricing value => scalableMatrixWithTieredPricing(value), + CumulativeGroupedBulk value => cumulativeGroupedBulk(value), + CumulativeGroupedAllocation value => cumulativeGroupedAllocation(value), + PriceMinimum value => minimum(value), + Percent value => percent(value), + EventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Price"), + }; + } + + public static implicit operator Price(Unit value) => new(value); + + public static implicit operator Price(Tiered value) => new(value); + + public static implicit operator Price(Bulk value) => new(value); + + public static implicit operator Price(BulkWithFilters value) => new(value); + + public static implicit operator Price(Package value) => new(value); + + public static implicit operator Price(Matrix value) => new(value); + + public static implicit operator Price(ThresholdTotalAmount value) => new(value); + + public static implicit operator Price(TieredPackage value) => new(value); + + public static implicit operator Price(TieredWithMinimum value) => new(value); + + public static implicit operator Price(GroupedTiered value) => new(value); + + public static implicit operator Price(TieredPackageWithMinimum value) => new(value); + + public static implicit operator Price(PackageWithAllocation value) => new(value); + + public static implicit operator Price(UnitWithPercent value) => new(value); + + public static implicit operator Price(MatrixWithAllocation value) => new(value); + + public static implicit operator Price(TieredWithProration value) => new(value); + + public static implicit operator Price(UnitWithProration value) => new(value); + + public static implicit operator Price(GroupedAllocation value) => new(value); + + public static implicit operator Price(BulkWithProration value) => new(value); + + public static implicit operator Price(GroupedWithProratedMinimum value) => new(value); + + public static implicit operator Price(GroupedWithMeteredMinimum value) => new(value); + + public static implicit operator Price(GroupedWithMinMaxThresholds value) => new(value); + + public static implicit operator Price(MatrixWithDisplayName value) => new(value); + + public static implicit operator Price(GroupedTieredPackage value) => new(value); + + public static implicit operator Price(MaxGroupTieredPackage value) => new(value); + + public static implicit operator Price(ScalableMatrixWithUnitPricing value) => new(value); + + public static implicit operator Price(ScalableMatrixWithTieredPricing value) => new(value); + + public static implicit operator Price(CumulativeGroupedBulk value) => new(value); + + public static implicit operator Price(CumulativeGroupedAllocation value) => new(value); + + public static implicit operator Price(PriceMinimum value) => new(value); + + public static implicit operator Price(Percent value) => new(value); + + public static implicit operator Price(EventOutput value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + this.Switch( + (unit) => unit.Validate(), + (tiered) => tiered.Validate(), + (bulk) => bulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (package) => package.Validate(), + (matrix) => matrix.Validate(), + (thresholdTotalAmount) => thresholdTotalAmount.Validate(), + (tieredPackage) => tieredPackage.Validate(), + (tieredWithMinimum) => tieredWithMinimum.Validate(), + (groupedTiered) => groupedTiered.Validate(), + (tieredPackageWithMinimum) => tieredPackageWithMinimum.Validate(), + (packageWithAllocation) => packageWithAllocation.Validate(), + (unitWithPercent) => unitWithPercent.Validate(), + (matrixWithAllocation) => matrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (unitWithProration) => unitWithProration.Validate(), + (groupedAllocation) => groupedAllocation.Validate(), + (bulkWithProration) => bulkWithProration.Validate(), + (groupedWithProratedMinimum) => groupedWithProratedMinimum.Validate(), + (groupedWithMeteredMinimum) => groupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (matrixWithDisplayName) => matrixWithDisplayName.Validate(), + (groupedTieredPackage) => groupedTieredPackage.Validate(), + (maxGroupTieredPackage) => maxGroupTieredPackage.Validate(), + (scalableMatrixWithUnitPricing) => scalableMatrixWithUnitPricing.Validate(), + (scalableMatrixWithTieredPricing) => scalableMatrixWithTieredPricing.Validate(), + (cumulativeGroupedBulk) => cumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (minimum) => minimum.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(Price? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceConverter : JsonConverter +{ + public override Price? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new Price(element); + } + } + } + + public override void Write(Utf8JsonWriter writer, Price value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Unit : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required UnitConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for unit pricing + /// + public required UnitConfig UnitConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_config"); } + init { JsonModel.Set(this._rawData, "unit_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"unit\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.UnitConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Unit() + { + this.ModelType = JsonSerializer.Deserialize("\"unit\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Unit(Unit unit) + : base(unit) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Unit(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"unit\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Unit(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Unit FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitFromRaw : IFromRawJson +{ + /// + public Unit FromRawUnchecked(IReadOnlyDictionary rawData) => + Unit.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BillingModeConverter))] +public enum BillingMode +{ + InAdvance, + InArrear, +} + +sealed class BillingModeConverter : JsonConverter +{ + public override BillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => BillingMode.InAdvance, + "in_arrear" => BillingMode.InArrear, + _ => (BillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BillingMode.InAdvance => "in_advance", + BillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(UnitCadenceConverter))] +public enum UnitCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class UnitCadenceConverter : JsonConverter +{ + public override UnitCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => UnitCadence.OneTime, + "monthly" => UnitCadence.Monthly, + "quarterly" => UnitCadence.Quarterly, + "semi_annual" => UnitCadence.SemiAnnual, + "annual" => UnitCadence.Annual, + "custom" => UnitCadence.Custom, + _ => (UnitCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitCadence.OneTime => "one_time", + UnitCadence.Monthly => "monthly", + UnitCadence.Quarterly => "quarterly", + UnitCadence.SemiAnnual => "semi_annual", + UnitCadence.Annual => "annual", + UnitCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public CompositePriceFilter() { } + + public CompositePriceFilter(CompositePriceFilter compositePriceFilter) + : base(compositePriceFilter) { } + + public CompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CompositePriceFilterFromRaw : IFromRawJson +{ + /// + public CompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(CompositePriceFilterFieldConverter))] +public enum CompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class CompositePriceFilterFieldConverter : JsonConverter +{ + public override CompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => CompositePriceFilterField.PriceID, + "item_id" => CompositePriceFilterField.ItemID, + "price_type" => CompositePriceFilterField.PriceType, + "currency" => CompositePriceFilterField.Currency, + "pricing_unit_id" => CompositePriceFilterField.PricingUnitID, + _ => (CompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CompositePriceFilterField.PriceID => "price_id", + CompositePriceFilterField.ItemID => "item_id", + CompositePriceFilterField.PriceType => "price_type", + CompositePriceFilterField.Currency => "currency", + CompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(CompositePriceFilterOperatorConverter))] +public enum CompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class CompositePriceFilterOperatorConverter : JsonConverter +{ + public override CompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => CompositePriceFilterOperator.Includes, + "excludes" => CompositePriceFilterOperator.Excludes, + _ => (CompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CompositePriceFilterOperator.Includes => "includes", + CompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(UnitConversionRateConfigConverter))] +public record class UnitConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public UnitConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public UnitConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public UnitConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of UnitConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of UnitConversionRateConfig" + ), + }; + } + + public static implicit operator UnitConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator UnitConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of UnitConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(UnitConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class UnitConversionRateConfigConverter : JsonConverter +{ + public override UnitConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new UnitConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + UnitConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(UnitPriceTypeConverter))] +public enum UnitPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class UnitPriceTypeConverter : JsonConverter +{ + public override UnitPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => UnitPriceType.UsagePrice, + "fixed_price" => UnitPriceType.FixedPrice, + "composite_price" => UnitPriceType.CompositePrice, + _ => (UnitPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitPriceType.UsagePrice => "usage_price", + UnitPriceType.FixedPrice => "fixed_price", + UnitPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Tiered : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required TieredConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for tiered pricing + /// + public required TieredConfig TieredConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "tiered_config"); } + init { JsonModel.Set(this._rawData, "tiered_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.TieredConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Tiered() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Tiered(Tiered tiered) + : base(tiered) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Tiered(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Tiered(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Tiered FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredFromRaw : IFromRawJson +{ + /// + public Tiered FromRawUnchecked(IReadOnlyDictionary rawData) => + Tiered.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TieredBillingModeConverter))] +public enum TieredBillingMode +{ + InAdvance, + InArrear, +} + +sealed class TieredBillingModeConverter : JsonConverter +{ + public override TieredBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => TieredBillingMode.InAdvance, + "in_arrear" => TieredBillingMode.InArrear, + _ => (TieredBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredBillingMode.InAdvance => "in_advance", + TieredBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredCadenceConverter))] +public enum TieredCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class TieredCadenceConverter : JsonConverter +{ + public override TieredCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => TieredCadence.OneTime, + "monthly" => TieredCadence.Monthly, + "quarterly" => TieredCadence.Quarterly, + "semi_annual" => TieredCadence.SemiAnnual, + "annual" => TieredCadence.Annual, + "custom" => TieredCadence.Custom, + _ => (TieredCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredCadence.OneTime => "one_time", + TieredCadence.Monthly => "monthly", + TieredCadence.Quarterly => "quarterly", + TieredCadence.SemiAnnual => "semi_annual", + TieredCadence.Annual => "annual", + TieredCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class TieredCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public TieredCompositePriceFilter() { } + + public TieredCompositePriceFilter(TieredCompositePriceFilter tieredCompositePriceFilter) + : base(tieredCompositePriceFilter) { } + + public TieredCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public TieredCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(TieredCompositePriceFilterFieldConverter))] +public enum TieredCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class TieredCompositePriceFilterFieldConverter + : JsonConverter +{ + public override TieredCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => TieredCompositePriceFilterField.PriceID, + "item_id" => TieredCompositePriceFilterField.ItemID, + "price_type" => TieredCompositePriceFilterField.PriceType, + "currency" => TieredCompositePriceFilterField.Currency, + "pricing_unit_id" => TieredCompositePriceFilterField.PricingUnitID, + _ => (TieredCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredCompositePriceFilterField.PriceID => "price_id", + TieredCompositePriceFilterField.ItemID => "item_id", + TieredCompositePriceFilterField.PriceType => "price_type", + TieredCompositePriceFilterField.Currency => "currency", + TieredCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(TieredCompositePriceFilterOperatorConverter))] +public enum TieredCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class TieredCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override TieredCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => TieredCompositePriceFilterOperator.Includes, + "excludes" => TieredCompositePriceFilterOperator.Excludes, + _ => (TieredCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredCompositePriceFilterOperator.Includes => "includes", + TieredCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredConversionRateConfigConverter))] +public record class TieredConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredConversionRateConfig" + ), + }; + } + + public static implicit operator TieredConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator TieredConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(TieredConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredConversionRateConfigConverter : JsonConverter +{ + public override TieredConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new TieredConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + TieredConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(TieredPriceTypeConverter))] +public enum TieredPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class TieredPriceTypeConverter : JsonConverter +{ + public override TieredPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => TieredPriceType.UsagePrice, + "fixed_price" => TieredPriceType.FixedPrice, + "composite_price" => TieredPriceType.CompositePrice, + _ => (TieredPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPriceType.UsagePrice => "usage_price", + TieredPriceType.FixedPrice => "fixed_price", + TieredPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Bulk : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + /// + /// Configuration for bulk pricing + /// + public required BulkConfig BulkConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "bulk_config"); } + init { JsonModel.Set(this._rawData, "bulk_config", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required BulkConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.BulkConfig.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Bulk() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Bulk(Bulk bulk) + : base(bulk) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Bulk(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Bulk(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Bulk FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkFromRaw : IFromRawJson +{ + /// + public Bulk FromRawUnchecked(IReadOnlyDictionary rawData) => + Bulk.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BulkBillingModeConverter))] +public enum BulkBillingMode +{ + InAdvance, + InArrear, +} + +sealed class BulkBillingModeConverter : JsonConverter +{ + public override BulkBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => BulkBillingMode.InAdvance, + "in_arrear" => BulkBillingMode.InArrear, + _ => (BulkBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkBillingMode.InAdvance => "in_advance", + BulkBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(BulkCadenceConverter))] +public enum BulkCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class BulkCadenceConverter : JsonConverter +{ + public override BulkCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => BulkCadence.OneTime, + "monthly" => BulkCadence.Monthly, + "quarterly" => BulkCadence.Quarterly, + "semi_annual" => BulkCadence.SemiAnnual, + "annual" => BulkCadence.Annual, + "custom" => BulkCadence.Custom, + _ => (BulkCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkCadence.OneTime => "one_time", + BulkCadence.Monthly => "monthly", + BulkCadence.Quarterly => "quarterly", + BulkCadence.SemiAnnual => "semi_annual", + BulkCadence.Annual => "annual", + BulkCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class BulkCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public BulkCompositePriceFilter() { } + + public BulkCompositePriceFilter(BulkCompositePriceFilter bulkCompositePriceFilter) + : base(bulkCompositePriceFilter) { } + + public BulkCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public BulkCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(BulkCompositePriceFilterFieldConverter))] +public enum BulkCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class BulkCompositePriceFilterFieldConverter : JsonConverter +{ + public override BulkCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => BulkCompositePriceFilterField.PriceID, + "item_id" => BulkCompositePriceFilterField.ItemID, + "price_type" => BulkCompositePriceFilterField.PriceType, + "currency" => BulkCompositePriceFilterField.Currency, + "pricing_unit_id" => BulkCompositePriceFilterField.PricingUnitID, + _ => (BulkCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkCompositePriceFilterField.PriceID => "price_id", + BulkCompositePriceFilterField.ItemID => "item_id", + BulkCompositePriceFilterField.PriceType => "price_type", + BulkCompositePriceFilterField.Currency => "currency", + BulkCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(BulkCompositePriceFilterOperatorConverter))] +public enum BulkCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class BulkCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override BulkCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => BulkCompositePriceFilterOperator.Includes, + "excludes" => BulkCompositePriceFilterOperator.Excludes, + _ => (BulkCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkCompositePriceFilterOperator.Includes => "includes", + BulkCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(BulkConversionRateConfigConverter))] +public record class BulkConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public BulkConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public BulkConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public BulkConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of BulkConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of BulkConversionRateConfig" + ), + }; + } + + public static implicit operator BulkConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator BulkConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of BulkConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(BulkConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class BulkConversionRateConfigConverter : JsonConverter +{ + public override BulkConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new BulkConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + BulkConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(BulkPriceTypeConverter))] +public enum BulkPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class BulkPriceTypeConverter : JsonConverter +{ + public override BulkPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => BulkPriceType.UsagePrice, + "fixed_price" => BulkPriceType.FixedPrice, + "composite_price" => BulkPriceType.CompositePrice, + _ => (BulkPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkPriceType.UsagePrice => "usage_price", + BulkPriceType.FixedPrice => "fixed_price", + BulkPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BulkWithFilters : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + /// + /// Configuration for bulk_with_filters pricing + /// + public required BulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required BulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public BulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public BulkWithFilters(BulkWithFilters bulkWithFilters) + : base(bulkWithFilters) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public BulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + BulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithFilters FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersFromRaw : IFromRawJson +{ + /// + public BulkWithFilters FromRawUnchecked(IReadOnlyDictionary rawData) => + BulkWithFilters.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BulkWithFiltersBillingModeConverter))] +public enum BulkWithFiltersBillingMode +{ + InAdvance, + InArrear, +} + +sealed class BulkWithFiltersBillingModeConverter : JsonConverter +{ + public override BulkWithFiltersBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => BulkWithFiltersBillingMode.InAdvance, + "in_arrear" => BulkWithFiltersBillingMode.InArrear, + _ => (BulkWithFiltersBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithFiltersBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithFiltersBillingMode.InAdvance => "in_advance", + BulkWithFiltersBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithFiltersConfig() { } + + public BulkWithFiltersConfig(BulkWithFiltersConfig bulkWithFiltersConfig) + : base(bulkWithFiltersConfig) { } + + public BulkWithFiltersConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFromRaw : IFromRawJson +{ + /// + public BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class BulkWithFiltersConfigFilter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public BulkWithFiltersConfigFilter() { } + + public BulkWithFiltersConfigFilter(BulkWithFiltersConfigFilter bulkWithFiltersConfigFilter) + : base(bulkWithFiltersConfigFilter) { } + + public BulkWithFiltersConfigFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfigFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFilterFromRaw : IFromRawJson +{ + /// + public BulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithFiltersConfigFilter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class BulkWithFiltersConfigTier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public BulkWithFiltersConfigTier() { } + + public BulkWithFiltersConfigTier(BulkWithFiltersConfigTier bulkWithFiltersConfigTier) + : base(bulkWithFiltersConfigTier) { } + + public BulkWithFiltersConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BulkWithFiltersConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class BulkWithFiltersConfigTierFromRaw : IFromRawJson +{ + /// + public BulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithFiltersConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BulkWithFiltersCadenceConverter))] +public enum BulkWithFiltersCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class BulkWithFiltersCadenceConverter : JsonConverter +{ + public override BulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => BulkWithFiltersCadence.OneTime, + "monthly" => BulkWithFiltersCadence.Monthly, + "quarterly" => BulkWithFiltersCadence.Quarterly, + "semi_annual" => BulkWithFiltersCadence.SemiAnnual, + "annual" => BulkWithFiltersCadence.Annual, + "custom" => BulkWithFiltersCadence.Custom, + _ => (BulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithFiltersCadence.OneTime => "one_time", + BulkWithFiltersCadence.Monthly => "monthly", + BulkWithFiltersCadence.Quarterly => "quarterly", + BulkWithFiltersCadence.SemiAnnual => "semi_annual", + BulkWithFiltersCadence.Annual => "annual", + BulkWithFiltersCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + BulkWithFiltersCompositePriceFilter, + BulkWithFiltersCompositePriceFilterFromRaw + >) +)] +public sealed record class BulkWithFiltersCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public BulkWithFiltersCompositePriceFilter() { } + + public BulkWithFiltersCompositePriceFilter( + BulkWithFiltersCompositePriceFilter bulkWithFiltersCompositePriceFilter + ) + : base(bulkWithFiltersCompositePriceFilter) { } + + public BulkWithFiltersCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithFiltersCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public BulkWithFiltersCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithFiltersCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(BulkWithFiltersCompositePriceFilterFieldConverter))] +public enum BulkWithFiltersCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class BulkWithFiltersCompositePriceFilterFieldConverter + : JsonConverter +{ + public override BulkWithFiltersCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => BulkWithFiltersCompositePriceFilterField.PriceID, + "item_id" => BulkWithFiltersCompositePriceFilterField.ItemID, + "price_type" => BulkWithFiltersCompositePriceFilterField.PriceType, + "currency" => BulkWithFiltersCompositePriceFilterField.Currency, + "pricing_unit_id" => BulkWithFiltersCompositePriceFilterField.PricingUnitID, + _ => (BulkWithFiltersCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithFiltersCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithFiltersCompositePriceFilterField.PriceID => "price_id", + BulkWithFiltersCompositePriceFilterField.ItemID => "item_id", + BulkWithFiltersCompositePriceFilterField.PriceType => "price_type", + BulkWithFiltersCompositePriceFilterField.Currency => "currency", + BulkWithFiltersCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(BulkWithFiltersCompositePriceFilterOperatorConverter))] +public enum BulkWithFiltersCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class BulkWithFiltersCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override BulkWithFiltersCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => BulkWithFiltersCompositePriceFilterOperator.Includes, + "excludes" => BulkWithFiltersCompositePriceFilterOperator.Excludes, + _ => (BulkWithFiltersCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithFiltersCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithFiltersCompositePriceFilterOperator.Includes => "includes", + BulkWithFiltersCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(BulkWithFiltersConversionRateConfigConverter))] +public record class BulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public BulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public BulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public BulkWithFiltersConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of BulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of BulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator BulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator BulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of BulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(BulkWithFiltersConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class BulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override BulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new BulkWithFiltersConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(BulkWithFiltersPriceTypeConverter))] +public enum BulkWithFiltersPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class BulkWithFiltersPriceTypeConverter : JsonConverter +{ + public override BulkWithFiltersPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => BulkWithFiltersPriceType.UsagePrice, + "fixed_price" => BulkWithFiltersPriceType.FixedPrice, + "composite_price" => BulkWithFiltersPriceType.CompositePrice, + _ => (BulkWithFiltersPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithFiltersPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithFiltersPriceType.UsagePrice => "usage_price", + BulkWithFiltersPriceType.FixedPrice => "fixed_price", + BulkWithFiltersPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Package : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required PackageConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for package pricing + /// + public required PackageConfig PackageConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_config"); } + init { JsonModel.Set(this._rawData, "package_config", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"package\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PackageConfig.Validate(); + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Package() + { + this.ModelType = JsonSerializer.Deserialize("\"package\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Package(Package package) + : base(package) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Package(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"package\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Package(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Package FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageFromRaw : IFromRawJson +{ + /// + public Package FromRawUnchecked(IReadOnlyDictionary rawData) => + Package.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PackageBillingModeConverter))] +public enum PackageBillingMode +{ + InAdvance, + InArrear, +} + +sealed class PackageBillingModeConverter : JsonConverter +{ + public override PackageBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => PackageBillingMode.InAdvance, + "in_arrear" => PackageBillingMode.InArrear, + _ => (PackageBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageBillingMode.InAdvance => "in_advance", + PackageBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PackageCadenceConverter))] +public enum PackageCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class PackageCadenceConverter : JsonConverter +{ + public override PackageCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => PackageCadence.OneTime, + "monthly" => PackageCadence.Monthly, + "quarterly" => PackageCadence.Quarterly, + "semi_annual" => PackageCadence.SemiAnnual, + "annual" => PackageCadence.Annual, + "custom" => PackageCadence.Custom, + _ => (PackageCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageCadence.OneTime => "one_time", + PackageCadence.Monthly => "monthly", + PackageCadence.Quarterly => "quarterly", + PackageCadence.SemiAnnual => "semi_annual", + PackageCadence.Annual => "annual", + PackageCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PackageCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PackageCompositePriceFilter() { } + + public PackageCompositePriceFilter(PackageCompositePriceFilter packageCompositePriceFilter) + : base(packageCompositePriceFilter) { } + + public PackageCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PackageCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public PackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PackageCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PackageCompositePriceFilterFieldConverter))] +public enum PackageCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PackageCompositePriceFilterFieldConverter + : JsonConverter +{ + public override PackageCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PackageCompositePriceFilterField.PriceID, + "item_id" => PackageCompositePriceFilterField.ItemID, + "price_type" => PackageCompositePriceFilterField.PriceType, + "currency" => PackageCompositePriceFilterField.Currency, + "pricing_unit_id" => PackageCompositePriceFilterField.PricingUnitID, + _ => (PackageCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageCompositePriceFilterField.PriceID => "price_id", + PackageCompositePriceFilterField.ItemID => "item_id", + PackageCompositePriceFilterField.PriceType => "price_type", + PackageCompositePriceFilterField.Currency => "currency", + PackageCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PackageCompositePriceFilterOperatorConverter))] +public enum PackageCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class PackageCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override PackageCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PackageCompositePriceFilterOperator.Includes, + "excludes" => PackageCompositePriceFilterOperator.Excludes, + _ => (PackageCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageCompositePriceFilterOperator.Includes => "includes", + PackageCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PackageConversionRateConfigConverter))] +public record class PackageConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PackageConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PackageConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PackageConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PackageConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PackageConversionRateConfig" + ), + }; + } + + public static implicit operator PackageConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PackageConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PackageConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PackageConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PackageConversionRateConfigConverter : JsonConverter +{ + public override PackageConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PackageConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PackageConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(PackagePriceTypeConverter))] +public enum PackagePriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class PackagePriceTypeConverter : JsonConverter +{ + public override PackagePriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => PackagePriceType.UsagePrice, + "fixed_price" => PackagePriceType.FixedPrice, + "composite_price" => PackagePriceType.CompositePrice, + _ => (PackagePriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackagePriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackagePriceType.UsagePrice => "usage_price", + PackagePriceType.FixedPrice => "fixed_price", + PackagePriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Matrix : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required MatrixConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + /// + /// Configuration for matrix pricing + /// + public required MatrixConfig MatrixConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "matrix_config"); } + init { JsonModel.Set(this._rawData, "matrix_config", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.MatrixConfig.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"matrix\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Matrix() + { + this.ModelType = JsonSerializer.Deserialize("\"matrix\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Matrix(Matrix matrix) + : base(matrix) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Matrix(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"matrix\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Matrix(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Matrix FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixFromRaw : IFromRawJson +{ + /// + public Matrix FromRawUnchecked(IReadOnlyDictionary rawData) => + Matrix.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MatrixBillingModeConverter))] +public enum MatrixBillingMode +{ + InAdvance, + InArrear, +} + +sealed class MatrixBillingModeConverter : JsonConverter +{ + public override MatrixBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => MatrixBillingMode.InAdvance, + "in_arrear" => MatrixBillingMode.InArrear, + _ => (MatrixBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixBillingMode.InAdvance => "in_advance", + MatrixBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MatrixCadenceConverter))] +public enum MatrixCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class MatrixCadenceConverter : JsonConverter +{ + public override MatrixCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => MatrixCadence.OneTime, + "monthly" => MatrixCadence.Monthly, + "quarterly" => MatrixCadence.Quarterly, + "semi_annual" => MatrixCadence.SemiAnnual, + "annual" => MatrixCadence.Annual, + "custom" => MatrixCadence.Custom, + _ => (MatrixCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixCadence.OneTime => "one_time", + MatrixCadence.Monthly => "monthly", + MatrixCadence.Quarterly => "quarterly", + MatrixCadence.SemiAnnual => "semi_annual", + MatrixCadence.Annual => "annual", + MatrixCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class MatrixCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MatrixCompositePriceFilter() { } + + public MatrixCompositePriceFilter(MatrixCompositePriceFilter matrixCompositePriceFilter) + : base(matrixCompositePriceFilter) { } + + public MatrixCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public MatrixCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MatrixCompositePriceFilterFieldConverter))] +public enum MatrixCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MatrixCompositePriceFilterFieldConverter + : JsonConverter +{ + public override MatrixCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MatrixCompositePriceFilterField.PriceID, + "item_id" => MatrixCompositePriceFilterField.ItemID, + "price_type" => MatrixCompositePriceFilterField.PriceType, + "currency" => MatrixCompositePriceFilterField.Currency, + "pricing_unit_id" => MatrixCompositePriceFilterField.PricingUnitID, + _ => (MatrixCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixCompositePriceFilterField.PriceID => "price_id", + MatrixCompositePriceFilterField.ItemID => "item_id", + MatrixCompositePriceFilterField.PriceType => "price_type", + MatrixCompositePriceFilterField.Currency => "currency", + MatrixCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MatrixCompositePriceFilterOperatorConverter))] +public enum MatrixCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class MatrixCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override MatrixCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MatrixCompositePriceFilterOperator.Includes, + "excludes" => MatrixCompositePriceFilterOperator.Excludes, + _ => (MatrixCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixCompositePriceFilterOperator.Includes => "includes", + MatrixCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MatrixConversionRateConfigConverter))] +public record class MatrixConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public MatrixConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MatrixConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MatrixConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of MatrixConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of MatrixConversionRateConfig" + ), + }; + } + + public static implicit operator MatrixConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator MatrixConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of MatrixConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(MatrixConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class MatrixConversionRateConfigConverter : JsonConverter +{ + public override MatrixConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new MatrixConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + MatrixConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(MatrixPriceTypeConverter))] +public enum MatrixPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class MatrixPriceTypeConverter : JsonConverter +{ + public override MatrixPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => MatrixPriceType.UsagePrice, + "fixed_price" => MatrixPriceType.FixedPrice, + "composite_price" => MatrixPriceType.CompositePrice, + _ => (MatrixPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixPriceType.UsagePrice => "usage_price", + MatrixPriceType.FixedPrice => "fixed_price", + MatrixPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ThresholdTotalAmount : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required ThresholdTotalAmountConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for threshold_total_amount pricing + /// + public required ThresholdTotalAmountThresholdTotalAmountConfig ThresholdTotalAmountConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "threshold_total_amount_config" + ); + } + init { JsonModel.Set(this._rawData, "threshold_total_amount_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"threshold_total_amount\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.ThresholdTotalAmountConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ThresholdTotalAmount() + { + this.ModelType = JsonSerializer.Deserialize("\"threshold_total_amount\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ThresholdTotalAmount(ThresholdTotalAmount thresholdTotalAmount) + : base(thresholdTotalAmount) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ThresholdTotalAmount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"threshold_total_amount\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + ThresholdTotalAmount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ThresholdTotalAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ThresholdTotalAmountFromRaw : IFromRawJson +{ + /// + public ThresholdTotalAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ThresholdTotalAmount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ThresholdTotalAmountBillingModeConverter))] +public enum ThresholdTotalAmountBillingMode +{ + InAdvance, + InArrear, +} + +sealed class ThresholdTotalAmountBillingModeConverter + : JsonConverter +{ + public override ThresholdTotalAmountBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => ThresholdTotalAmountBillingMode.InAdvance, + "in_arrear" => ThresholdTotalAmountBillingMode.InArrear, + _ => (ThresholdTotalAmountBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ThresholdTotalAmountBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ThresholdTotalAmountBillingMode.InAdvance => "in_advance", + ThresholdTotalAmountBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ThresholdTotalAmountCadenceConverter))] +public enum ThresholdTotalAmountCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class ThresholdTotalAmountCadenceConverter : JsonConverter +{ + public override ThresholdTotalAmountCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => ThresholdTotalAmountCadence.OneTime, + "monthly" => ThresholdTotalAmountCadence.Monthly, + "quarterly" => ThresholdTotalAmountCadence.Quarterly, + "semi_annual" => ThresholdTotalAmountCadence.SemiAnnual, + "annual" => ThresholdTotalAmountCadence.Annual, + "custom" => ThresholdTotalAmountCadence.Custom, + _ => (ThresholdTotalAmountCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ThresholdTotalAmountCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ThresholdTotalAmountCadence.OneTime => "one_time", + ThresholdTotalAmountCadence.Monthly => "monthly", + ThresholdTotalAmountCadence.Quarterly => "quarterly", + ThresholdTotalAmountCadence.SemiAnnual => "semi_annual", + ThresholdTotalAmountCadence.Annual => "annual", + ThresholdTotalAmountCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ThresholdTotalAmountCompositePriceFilter, + ThresholdTotalAmountCompositePriceFilterFromRaw + >) +)] +public sealed record class ThresholdTotalAmountCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public ThresholdTotalAmountCompositePriceFilter() { } + + public ThresholdTotalAmountCompositePriceFilter( + ThresholdTotalAmountCompositePriceFilter thresholdTotalAmountCompositePriceFilter + ) + : base(thresholdTotalAmountCompositePriceFilter) { } + + public ThresholdTotalAmountCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ThresholdTotalAmountCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ThresholdTotalAmountCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ThresholdTotalAmountCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public ThresholdTotalAmountCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ThresholdTotalAmountCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(ThresholdTotalAmountCompositePriceFilterFieldConverter))] +public enum ThresholdTotalAmountCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class ThresholdTotalAmountCompositePriceFilterFieldConverter + : JsonConverter +{ + public override ThresholdTotalAmountCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => ThresholdTotalAmountCompositePriceFilterField.PriceID, + "item_id" => ThresholdTotalAmountCompositePriceFilterField.ItemID, + "price_type" => ThresholdTotalAmountCompositePriceFilterField.PriceType, + "currency" => ThresholdTotalAmountCompositePriceFilterField.Currency, + "pricing_unit_id" => ThresholdTotalAmountCompositePriceFilterField.PricingUnitID, + _ => (ThresholdTotalAmountCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ThresholdTotalAmountCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ThresholdTotalAmountCompositePriceFilterField.PriceID => "price_id", + ThresholdTotalAmountCompositePriceFilterField.ItemID => "item_id", + ThresholdTotalAmountCompositePriceFilterField.PriceType => "price_type", + ThresholdTotalAmountCompositePriceFilterField.Currency => "currency", + ThresholdTotalAmountCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(ThresholdTotalAmountCompositePriceFilterOperatorConverter))] +public enum ThresholdTotalAmountCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class ThresholdTotalAmountCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override ThresholdTotalAmountCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => ThresholdTotalAmountCompositePriceFilterOperator.Includes, + "excludes" => ThresholdTotalAmountCompositePriceFilterOperator.Excludes, + _ => (ThresholdTotalAmountCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ThresholdTotalAmountCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ThresholdTotalAmountCompositePriceFilterOperator.Includes => "includes", + ThresholdTotalAmountCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ThresholdTotalAmountConversionRateConfigConverter))] +public record class ThresholdTotalAmountConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ThresholdTotalAmountConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ThresholdTotalAmountConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ThresholdTotalAmountConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ThresholdTotalAmountConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ThresholdTotalAmountConversionRateConfig" + ), + }; + } + + public static implicit operator ThresholdTotalAmountConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ThresholdTotalAmountConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ThresholdTotalAmountConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ThresholdTotalAmountConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ThresholdTotalAmountConversionRateConfigConverter + : JsonConverter +{ + public override ThresholdTotalAmountConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ThresholdTotalAmountConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ThresholdTotalAmountConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(ThresholdTotalAmountPriceTypeConverter))] +public enum ThresholdTotalAmountPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class ThresholdTotalAmountPriceTypeConverter : JsonConverter +{ + public override ThresholdTotalAmountPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => ThresholdTotalAmountPriceType.UsagePrice, + "fixed_price" => ThresholdTotalAmountPriceType.FixedPrice, + "composite_price" => ThresholdTotalAmountPriceType.CompositePrice, + _ => (ThresholdTotalAmountPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ThresholdTotalAmountPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ThresholdTotalAmountPriceType.UsagePrice => "usage_price", + ThresholdTotalAmountPriceType.FixedPrice => "fixed_price", + ThresholdTotalAmountPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for threshold_total_amount pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ThresholdTotalAmountThresholdTotalAmountConfig, + ThresholdTotalAmountThresholdTotalAmountConfigFromRaw + >) +)] +public sealed record class ThresholdTotalAmountThresholdTotalAmountConfig : JsonModel +{ + /// + /// When the quantity consumed passes a provided threshold, the configured total + /// will be charged + /// + public required IReadOnlyList ConsumptionTable + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "consumption_table"); + } + init { JsonModel.Set(this._rawData, "consumption_table", value); } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.ConsumptionTable) + { + item.Validate(); + } + _ = this.Prorate; + } + + public ThresholdTotalAmountThresholdTotalAmountConfig() { } + + public ThresholdTotalAmountThresholdTotalAmountConfig( + ThresholdTotalAmountThresholdTotalAmountConfig thresholdTotalAmountThresholdTotalAmountConfig + ) + : base(thresholdTotalAmountThresholdTotalAmountConfig) { } + + public ThresholdTotalAmountThresholdTotalAmountConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ThresholdTotalAmountThresholdTotalAmountConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ThresholdTotalAmountThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ThresholdTotalAmountThresholdTotalAmountConfig( + List consumptionTable + ) + : this() + { + this.ConsumptionTable = consumptionTable; + } +} + +class ThresholdTotalAmountThresholdTotalAmountConfigFromRaw + : IFromRawJson +{ + /// + public ThresholdTotalAmountThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ThresholdTotalAmountThresholdTotalAmountConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single threshold +/// +[JsonConverter( + typeof(JsonModelConverter< + ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable, + ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTableFromRaw + >) +)] +public sealed record class ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable + : JsonModel +{ + /// + /// Quantity threshold + /// + public required string Threshold + { + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } + } + + /// + /// Total amount for this threshold + /// + public required string TotalAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "total_amount"); } + init { JsonModel.Set(this._rawData, "total_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Threshold; + _ = this.TotalAmount; + } + + public ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable() { } + + public ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable( + ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable thresholdTotalAmountThresholdTotalAmountConfigConsumptionTable + ) + : base(thresholdTotalAmountThresholdTotalAmountConfigConsumptionTable) { } + + public ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTableFromRaw + : IFromRawJson +{ + /// + public ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ThresholdTotalAmountThresholdTotalAmountConfigConsumptionTable.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredPackage : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required TieredPackageConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for tiered_package pricing + /// + public required TieredPackageTieredPackageConfig TieredPackageConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_package_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_package\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.TieredPackageConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredPackage() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_package\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredPackage(TieredPackage tieredPackage) + : base(tieredPackage) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredPackage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_package\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + TieredPackage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackage FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageFromRaw : IFromRawJson +{ + /// + public TieredPackage FromRawUnchecked(IReadOnlyDictionary rawData) => + TieredPackage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TieredPackageBillingModeConverter))] +public enum TieredPackageBillingMode +{ + InAdvance, + InArrear, +} + +sealed class TieredPackageBillingModeConverter : JsonConverter +{ + public override TieredPackageBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => TieredPackageBillingMode.InAdvance, + "in_arrear" => TieredPackageBillingMode.InArrear, + _ => (TieredPackageBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageBillingMode.InAdvance => "in_advance", + TieredPackageBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredPackageCadenceConverter))] +public enum TieredPackageCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class TieredPackageCadenceConverter : JsonConverter +{ + public override TieredPackageCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => TieredPackageCadence.OneTime, + "monthly" => TieredPackageCadence.Monthly, + "quarterly" => TieredPackageCadence.Quarterly, + "semi_annual" => TieredPackageCadence.SemiAnnual, + "annual" => TieredPackageCadence.Annual, + "custom" => TieredPackageCadence.Custom, + _ => (TieredPackageCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageCadence.OneTime => "one_time", + TieredPackageCadence.Monthly => "monthly", + TieredPackageCadence.Quarterly => "quarterly", + TieredPackageCadence.SemiAnnual => "semi_annual", + TieredPackageCadence.Annual => "annual", + TieredPackageCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageCompositePriceFilter, + TieredPackageCompositePriceFilterFromRaw + >) +)] +public sealed record class TieredPackageCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public TieredPackageCompositePriceFilter() { } + + public TieredPackageCompositePriceFilter( + TieredPackageCompositePriceFilter tieredPackageCompositePriceFilter + ) + : base(tieredPackageCompositePriceFilter) { } + + public TieredPackageCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public TieredPackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(TieredPackageCompositePriceFilterFieldConverter))] +public enum TieredPackageCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class TieredPackageCompositePriceFilterFieldConverter + : JsonConverter +{ + public override TieredPackageCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => TieredPackageCompositePriceFilterField.PriceID, + "item_id" => TieredPackageCompositePriceFilterField.ItemID, + "price_type" => TieredPackageCompositePriceFilterField.PriceType, + "currency" => TieredPackageCompositePriceFilterField.Currency, + "pricing_unit_id" => TieredPackageCompositePriceFilterField.PricingUnitID, + _ => (TieredPackageCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageCompositePriceFilterField.PriceID => "price_id", + TieredPackageCompositePriceFilterField.ItemID => "item_id", + TieredPackageCompositePriceFilterField.PriceType => "price_type", + TieredPackageCompositePriceFilterField.Currency => "currency", + TieredPackageCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(TieredPackageCompositePriceFilterOperatorConverter))] +public enum TieredPackageCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class TieredPackageCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override TieredPackageCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => TieredPackageCompositePriceFilterOperator.Includes, + "excludes" => TieredPackageCompositePriceFilterOperator.Excludes, + _ => (TieredPackageCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageCompositePriceFilterOperator.Includes => "includes", + TieredPackageCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredPackageConversionRateConfigConverter))] +public record class TieredPackageConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredPackageConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredPackageConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredPackageConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredPackageConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredPackageConversionRateConfig" + ), + }; + } + + public static implicit operator TieredPackageConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator TieredPackageConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredPackageConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(TieredPackageConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredPackageConversionRateConfigConverter + : JsonConverter +{ + public override TieredPackageConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new TieredPackageConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(TieredPackagePriceTypeConverter))] +public enum TieredPackagePriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class TieredPackagePriceTypeConverter : JsonConverter +{ + public override TieredPackagePriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => TieredPackagePriceType.UsagePrice, + "fixed_price" => TieredPackagePriceType.FixedPrice, + "composite_price" => TieredPackagePriceType.CompositePrice, + _ => (TieredPackagePriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackagePriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackagePriceType.UsagePrice => "usage_price", + TieredPackagePriceType.FixedPrice => "fixed_price", + TieredPackagePriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageTieredPackageConfig, + TieredPackageTieredPackageConfigFromRaw + >) +)] +public sealed record class TieredPackageTieredPackageConfig : JsonModel +{ + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. The tier bounds are defined + /// based on the total quantity rather than the number of packages, so they must + /// be multiples of the package size. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredPackageTieredPackageConfig() { } + + public TieredPackageTieredPackageConfig( + TieredPackageTieredPackageConfig tieredPackageTieredPackageConfig + ) + : base(tieredPackageTieredPackageConfig) { } + + public TieredPackageTieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageTieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageTieredPackageConfigFromRaw : IFromRawJson +{ + /// + public TieredPackageTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageTieredPackageConfigTier, + TieredPackageTieredPackageConfigTierFromRaw + >) +)] +public sealed record class TieredPackageTieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public TieredPackageTieredPackageConfigTier() { } + + public TieredPackageTieredPackageConfigTier( + TieredPackageTieredPackageConfigTier tieredPackageTieredPackageConfigTier + ) + : base(tieredPackageTieredPackageConfigTier) { } + + public TieredPackageTieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageTieredPackageConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public TieredPackageTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredWithMinimum : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required TieredWithMinimumConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for tiered_with_minimum pricing + /// + public required TieredWithMinimumTieredWithMinimumConfig TieredWithMinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_minimum_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_minimum\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.TieredWithMinimumConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredWithMinimum() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_minimum\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredWithMinimum(TieredWithMinimum tieredWithMinimum) + : base(tieredWithMinimum) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredWithMinimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_minimum\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + TieredWithMinimum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithMinimumFromRaw : IFromRawJson +{ + /// + public TieredWithMinimum FromRawUnchecked(IReadOnlyDictionary rawData) => + TieredWithMinimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TieredWithMinimumBillingModeConverter))] +public enum TieredWithMinimumBillingMode +{ + InAdvance, + InArrear, +} + +sealed class TieredWithMinimumBillingModeConverter : JsonConverter +{ + public override TieredWithMinimumBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => TieredWithMinimumBillingMode.InAdvance, + "in_arrear" => TieredWithMinimumBillingMode.InArrear, + _ => (TieredWithMinimumBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithMinimumBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithMinimumBillingMode.InAdvance => "in_advance", + TieredWithMinimumBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredWithMinimumCadenceConverter))] +public enum TieredWithMinimumCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class TieredWithMinimumCadenceConverter : JsonConverter +{ + public override TieredWithMinimumCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => TieredWithMinimumCadence.OneTime, + "monthly" => TieredWithMinimumCadence.Monthly, + "quarterly" => TieredWithMinimumCadence.Quarterly, + "semi_annual" => TieredWithMinimumCadence.SemiAnnual, + "annual" => TieredWithMinimumCadence.Annual, + "custom" => TieredWithMinimumCadence.Custom, + _ => (TieredWithMinimumCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithMinimumCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithMinimumCadence.OneTime => "one_time", + TieredWithMinimumCadence.Monthly => "monthly", + TieredWithMinimumCadence.Quarterly => "quarterly", + TieredWithMinimumCadence.SemiAnnual => "semi_annual", + TieredWithMinimumCadence.Annual => "annual", + TieredWithMinimumCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + TieredWithMinimumCompositePriceFilter, + TieredWithMinimumCompositePriceFilterFromRaw + >) +)] +public sealed record class TieredWithMinimumCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public TieredWithMinimumCompositePriceFilter() { } + + public TieredWithMinimumCompositePriceFilter( + TieredWithMinimumCompositePriceFilter tieredWithMinimumCompositePriceFilter + ) + : base(tieredWithMinimumCompositePriceFilter) { } + + public TieredWithMinimumCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithMinimumCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithMinimumCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public TieredWithMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithMinimumCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(TieredWithMinimumCompositePriceFilterFieldConverter))] +public enum TieredWithMinimumCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class TieredWithMinimumCompositePriceFilterFieldConverter + : JsonConverter +{ + public override TieredWithMinimumCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => TieredWithMinimumCompositePriceFilterField.PriceID, + "item_id" => TieredWithMinimumCompositePriceFilterField.ItemID, + "price_type" => TieredWithMinimumCompositePriceFilterField.PriceType, + "currency" => TieredWithMinimumCompositePriceFilterField.Currency, + "pricing_unit_id" => TieredWithMinimumCompositePriceFilterField.PricingUnitID, + _ => (TieredWithMinimumCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithMinimumCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithMinimumCompositePriceFilterField.PriceID => "price_id", + TieredWithMinimumCompositePriceFilterField.ItemID => "item_id", + TieredWithMinimumCompositePriceFilterField.PriceType => "price_type", + TieredWithMinimumCompositePriceFilterField.Currency => "currency", + TieredWithMinimumCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(TieredWithMinimumCompositePriceFilterOperatorConverter))] +public enum TieredWithMinimumCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class TieredWithMinimumCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override TieredWithMinimumCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => TieredWithMinimumCompositePriceFilterOperator.Includes, + "excludes" => TieredWithMinimumCompositePriceFilterOperator.Excludes, + _ => (TieredWithMinimumCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithMinimumCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithMinimumCompositePriceFilterOperator.Includes => "includes", + TieredWithMinimumCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredWithMinimumConversionRateConfigConverter))] +public record class TieredWithMinimumConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredWithMinimumConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithMinimumConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithMinimumConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithMinimumConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithMinimumConversionRateConfig" + ), + }; + } + + public static implicit operator TieredWithMinimumConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator TieredWithMinimumConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithMinimumConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(TieredWithMinimumConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredWithMinimumConversionRateConfigConverter + : JsonConverter +{ + public override TieredWithMinimumConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new TieredWithMinimumConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithMinimumConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(TieredWithMinimumPriceTypeConverter))] +public enum TieredWithMinimumPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class TieredWithMinimumPriceTypeConverter : JsonConverter +{ + public override TieredWithMinimumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => TieredWithMinimumPriceType.UsagePrice, + "fixed_price" => TieredWithMinimumPriceType.FixedPrice, + "composite_price" => TieredWithMinimumPriceType.CompositePrice, + _ => (TieredWithMinimumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithMinimumPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithMinimumPriceType.UsagePrice => "usage_price", + TieredWithMinimumPriceType.FixedPrice => "fixed_price", + TieredWithMinimumPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredWithMinimumTieredWithMinimumConfig, + TieredWithMinimumTieredWithMinimumConfigFromRaw + >) +)] +public sealed record class TieredWithMinimumTieredWithMinimumConfig : JsonModel +{ + /// + /// Tiered pricing with a minimum amount dependent on the volume tier. Tiers + /// are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// If true, tiers with an accrued amount of 0 will not be included in the rating. + /// + public bool? HideZeroAmountTiers + { + get { return JsonModel.GetNullableStruct(this.RawData, "hide_zero_amount_tiers"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "hide_zero_amount_tiers", value); + } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorate", value); + } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.HideZeroAmountTiers; + _ = this.Prorate; + } + + public TieredWithMinimumTieredWithMinimumConfig() { } + + public TieredWithMinimumTieredWithMinimumConfig( + TieredWithMinimumTieredWithMinimumConfig tieredWithMinimumTieredWithMinimumConfig + ) + : base(tieredWithMinimumTieredWithMinimumConfig) { } + + public TieredWithMinimumTieredWithMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithMinimumTieredWithMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithMinimumTieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithMinimumTieredWithMinimumConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithMinimumTieredWithMinimumConfigFromRaw + : IFromRawJson +{ + /// + public TieredWithMinimumTieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithMinimumTieredWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredWithMinimumTieredWithMinimumConfigTier, + TieredWithMinimumTieredWithMinimumConfigTierFromRaw + >) +)] +public sealed record class TieredWithMinimumTieredWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithMinimumTieredWithMinimumConfigTier() { } + + public TieredWithMinimumTieredWithMinimumConfigTier( + TieredWithMinimumTieredWithMinimumConfigTier tieredWithMinimumTieredWithMinimumConfigTier + ) + : base(tieredWithMinimumTieredWithMinimumConfigTier) { } + + public TieredWithMinimumTieredWithMinimumConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithMinimumTieredWithMinimumConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithMinimumTieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithMinimumTieredWithMinimumConfigTierFromRaw + : IFromRawJson +{ + /// + public TieredWithMinimumTieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithMinimumTieredWithMinimumConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class GroupedTiered : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required GroupedTieredConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// Configuration for grouped_tiered pricing + /// + public required GroupedTieredGroupedTieredConfig GroupedTieredConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_tiered_config", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.GroupedTieredConfig.Validate(); + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_tiered\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedTiered() + { + this.ModelType = JsonSerializer.Deserialize("\"grouped_tiered\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedTiered(GroupedTiered groupedTiered) + : base(groupedTiered) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedTiered(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"grouped_tiered\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + GroupedTiered(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTiered FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredFromRaw : IFromRawJson +{ + /// + public GroupedTiered FromRawUnchecked(IReadOnlyDictionary rawData) => + GroupedTiered.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedTieredBillingModeConverter))] +public enum GroupedTieredBillingMode +{ + InAdvance, + InArrear, +} + +sealed class GroupedTieredBillingModeConverter : JsonConverter +{ + public override GroupedTieredBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => GroupedTieredBillingMode.InAdvance, + "in_arrear" => GroupedTieredBillingMode.InArrear, + _ => (GroupedTieredBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredBillingMode.InAdvance => "in_advance", + GroupedTieredBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedTieredCadenceConverter))] +public enum GroupedTieredCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class GroupedTieredCadenceConverter : JsonConverter +{ + public override GroupedTieredCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => GroupedTieredCadence.OneTime, + "monthly" => GroupedTieredCadence.Monthly, + "quarterly" => GroupedTieredCadence.Quarterly, + "semi_annual" => GroupedTieredCadence.SemiAnnual, + "annual" => GroupedTieredCadence.Annual, + "custom" => GroupedTieredCadence.Custom, + _ => (GroupedTieredCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredCadence.OneTime => "one_time", + GroupedTieredCadence.Monthly => "monthly", + GroupedTieredCadence.Quarterly => "quarterly", + GroupedTieredCadence.SemiAnnual => "semi_annual", + GroupedTieredCadence.Annual => "annual", + GroupedTieredCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredCompositePriceFilter, + GroupedTieredCompositePriceFilterFromRaw + >) +)] +public sealed record class GroupedTieredCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public GroupedTieredCompositePriceFilter() { } + + public GroupedTieredCompositePriceFilter( + GroupedTieredCompositePriceFilter groupedTieredCompositePriceFilter + ) + : base(groupedTieredCompositePriceFilter) { } + + public GroupedTieredCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public GroupedTieredCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(GroupedTieredCompositePriceFilterFieldConverter))] +public enum GroupedTieredCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class GroupedTieredCompositePriceFilterFieldConverter + : JsonConverter +{ + public override GroupedTieredCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => GroupedTieredCompositePriceFilterField.PriceID, + "item_id" => GroupedTieredCompositePriceFilterField.ItemID, + "price_type" => GroupedTieredCompositePriceFilterField.PriceType, + "currency" => GroupedTieredCompositePriceFilterField.Currency, + "pricing_unit_id" => GroupedTieredCompositePriceFilterField.PricingUnitID, + _ => (GroupedTieredCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredCompositePriceFilterField.PriceID => "price_id", + GroupedTieredCompositePriceFilterField.ItemID => "item_id", + GroupedTieredCompositePriceFilterField.PriceType => "price_type", + GroupedTieredCompositePriceFilterField.Currency => "currency", + GroupedTieredCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(GroupedTieredCompositePriceFilterOperatorConverter))] +public enum GroupedTieredCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class GroupedTieredCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override GroupedTieredCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => GroupedTieredCompositePriceFilterOperator.Includes, + "excludes" => GroupedTieredCompositePriceFilterOperator.Excludes, + _ => (GroupedTieredCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredCompositePriceFilterOperator.Includes => "includes", + GroupedTieredCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedTieredConversionRateConfigConverter))] +public record class GroupedTieredConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedTieredConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedTieredConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedTieredConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedTieredConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedTieredConversionRateConfig" + ), + }; + } + + public static implicit operator GroupedTieredConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator GroupedTieredConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedTieredConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(GroupedTieredConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedTieredConversionRateConfigConverter + : JsonConverter +{ + public override GroupedTieredConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new GroupedTieredConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for grouped_tiered pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredGroupedTieredConfig, + GroupedTieredGroupedTieredConfigFromRaw + >) +)] +public sealed record class GroupedTieredGroupedTieredConfig : JsonModel +{ + /// + /// The billable metric property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Apply tiered pricing to each segment generated after grouping with the provided key + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public GroupedTieredGroupedTieredConfig() { } + + public GroupedTieredGroupedTieredConfig( + GroupedTieredGroupedTieredConfig groupedTieredGroupedTieredConfig + ) + : base(groupedTieredGroupedTieredConfig) { } + + public GroupedTieredGroupedTieredConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredGroupedTieredConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredGroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredGroupedTieredConfigFromRaw : IFromRawJson +{ + /// + public GroupedTieredGroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredGroupedTieredConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredGroupedTieredConfigTier, + GroupedTieredGroupedTieredConfigTierFromRaw + >) +)] +public sealed record class GroupedTieredGroupedTieredConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public GroupedTieredGroupedTieredConfigTier() { } + + public GroupedTieredGroupedTieredConfigTier( + GroupedTieredGroupedTieredConfigTier groupedTieredGroupedTieredConfigTier + ) + : base(groupedTieredGroupedTieredConfigTier) { } + + public GroupedTieredGroupedTieredConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredGroupedTieredConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredGroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredGroupedTieredConfigTierFromRaw + : IFromRawJson +{ + /// + public GroupedTieredGroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredGroupedTieredConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedTieredPriceTypeConverter))] +public enum GroupedTieredPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class GroupedTieredPriceTypeConverter : JsonConverter +{ + public override GroupedTieredPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => GroupedTieredPriceType.UsagePrice, + "fixed_price" => GroupedTieredPriceType.FixedPrice, + "composite_price" => GroupedTieredPriceType.CompositePrice, + _ => (GroupedTieredPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredPriceType.UsagePrice => "usage_price", + GroupedTieredPriceType.FixedPrice => "fixed_price", + GroupedTieredPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class TieredPackageWithMinimum : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required TieredPackageWithMinimumConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for tiered_package_with_minimum pricing + /// + public required TieredPackageWithMinimumTieredPackageWithMinimumConfig TieredPackageWithMinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_with_minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_package_with_minimum_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_package_with_minimum\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.TieredPackageWithMinimumConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredPackageWithMinimum() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_package_with_minimum\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredPackageWithMinimum(TieredPackageWithMinimum tieredPackageWithMinimum) + : base(tieredPackageWithMinimum) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredPackageWithMinimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_package_with_minimum\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + TieredPackageWithMinimum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageWithMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumFromRaw : IFromRawJson +{ + /// + public TieredPackageWithMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageWithMinimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TieredPackageWithMinimumBillingModeConverter))] +public enum TieredPackageWithMinimumBillingMode +{ + InAdvance, + InArrear, +} + +sealed class TieredPackageWithMinimumBillingModeConverter + : JsonConverter +{ + public override TieredPackageWithMinimumBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => TieredPackageWithMinimumBillingMode.InAdvance, + "in_arrear" => TieredPackageWithMinimumBillingMode.InArrear, + _ => (TieredPackageWithMinimumBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageWithMinimumBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageWithMinimumBillingMode.InAdvance => "in_advance", + TieredPackageWithMinimumBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredPackageWithMinimumCadenceConverter))] +public enum TieredPackageWithMinimumCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class TieredPackageWithMinimumCadenceConverter + : JsonConverter +{ + public override TieredPackageWithMinimumCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => TieredPackageWithMinimumCadence.OneTime, + "monthly" => TieredPackageWithMinimumCadence.Monthly, + "quarterly" => TieredPackageWithMinimumCadence.Quarterly, + "semi_annual" => TieredPackageWithMinimumCadence.SemiAnnual, + "annual" => TieredPackageWithMinimumCadence.Annual, + "custom" => TieredPackageWithMinimumCadence.Custom, + _ => (TieredPackageWithMinimumCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageWithMinimumCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageWithMinimumCadence.OneTime => "one_time", + TieredPackageWithMinimumCadence.Monthly => "monthly", + TieredPackageWithMinimumCadence.Quarterly => "quarterly", + TieredPackageWithMinimumCadence.SemiAnnual => "semi_annual", + TieredPackageWithMinimumCadence.Annual => "annual", + TieredPackageWithMinimumCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageWithMinimumCompositePriceFilter, + TieredPackageWithMinimumCompositePriceFilterFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public TieredPackageWithMinimumCompositePriceFilter() { } + + public TieredPackageWithMinimumCompositePriceFilter( + TieredPackageWithMinimumCompositePriceFilter tieredPackageWithMinimumCompositePriceFilter + ) + : base(tieredPackageWithMinimumCompositePriceFilter) { } + + public TieredPackageWithMinimumCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageWithMinimumCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageWithMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public TieredPackageWithMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageWithMinimumCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(TieredPackageWithMinimumCompositePriceFilterFieldConverter))] +public enum TieredPackageWithMinimumCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class TieredPackageWithMinimumCompositePriceFilterFieldConverter + : JsonConverter +{ + public override TieredPackageWithMinimumCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => TieredPackageWithMinimumCompositePriceFilterField.PriceID, + "item_id" => TieredPackageWithMinimumCompositePriceFilterField.ItemID, + "price_type" => TieredPackageWithMinimumCompositePriceFilterField.PriceType, + "currency" => TieredPackageWithMinimumCompositePriceFilterField.Currency, + "pricing_unit_id" => TieredPackageWithMinimumCompositePriceFilterField.PricingUnitID, + _ => (TieredPackageWithMinimumCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageWithMinimumCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageWithMinimumCompositePriceFilterField.PriceID => "price_id", + TieredPackageWithMinimumCompositePriceFilterField.ItemID => "item_id", + TieredPackageWithMinimumCompositePriceFilterField.PriceType => "price_type", + TieredPackageWithMinimumCompositePriceFilterField.Currency => "currency", + TieredPackageWithMinimumCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(TieredPackageWithMinimumCompositePriceFilterOperatorConverter))] +public enum TieredPackageWithMinimumCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class TieredPackageWithMinimumCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override TieredPackageWithMinimumCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => TieredPackageWithMinimumCompositePriceFilterOperator.Includes, + "excludes" => TieredPackageWithMinimumCompositePriceFilterOperator.Excludes, + _ => (TieredPackageWithMinimumCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageWithMinimumCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageWithMinimumCompositePriceFilterOperator.Includes => "includes", + TieredPackageWithMinimumCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredPackageWithMinimumConversionRateConfigConverter))] +public record class TieredPackageWithMinimumConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredPackageWithMinimumConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredPackageWithMinimumConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredPackageWithMinimumConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredPackageWithMinimumConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredPackageWithMinimumConversionRateConfig" + ), + }; + } + + public static implicit operator TieredPackageWithMinimumConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator TieredPackageWithMinimumConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredPackageWithMinimumConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(TieredPackageWithMinimumConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredPackageWithMinimumConversionRateConfigConverter + : JsonConverter +{ + public override TieredPackageWithMinimumConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new TieredPackageWithMinimumConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageWithMinimumConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(TieredPackageWithMinimumPriceTypeConverter))] +public enum TieredPackageWithMinimumPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class TieredPackageWithMinimumPriceTypeConverter + : JsonConverter +{ + public override TieredPackageWithMinimumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => TieredPackageWithMinimumPriceType.UsagePrice, + "fixed_price" => TieredPackageWithMinimumPriceType.FixedPrice, + "composite_price" => TieredPackageWithMinimumPriceType.CompositePrice, + _ => (TieredPackageWithMinimumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredPackageWithMinimumPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredPackageWithMinimumPriceType.UsagePrice => "usage_price", + TieredPackageWithMinimumPriceType.FixedPrice => "fixed_price", + TieredPackageWithMinimumPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageWithMinimumTieredPackageWithMinimumConfig, + TieredPackageWithMinimumTieredPackageWithMinimumConfigFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumTieredPackageWithMinimumConfig : JsonModel +{ + /// + /// Package size + /// + public required double PackageSize + { + get { return JsonModel.GetNotNullStruct(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredPackageWithMinimumTieredPackageWithMinimumConfig() { } + + public TieredPackageWithMinimumTieredPackageWithMinimumConfig( + TieredPackageWithMinimumTieredPackageWithMinimumConfig tieredPackageWithMinimumTieredPackageWithMinimumConfig + ) + : base(tieredPackageWithMinimumTieredPackageWithMinimumConfig) { } + + public TieredPackageWithMinimumTieredPackageWithMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageWithMinimumTieredPackageWithMinimumConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageWithMinimumTieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumTieredPackageWithMinimumConfigFromRaw + : IFromRawJson +{ + /// + public TieredPackageWithMinimumTieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageWithMinimumTieredPackageWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredPackageWithMinimumTieredPackageWithMinimumConfigTier, + TieredPackageWithMinimumTieredPackageWithMinimumConfigTierFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumTieredPackageWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public TieredPackageWithMinimumTieredPackageWithMinimumConfigTier() { } + + public TieredPackageWithMinimumTieredPackageWithMinimumConfigTier( + TieredPackageWithMinimumTieredPackageWithMinimumConfigTier tieredPackageWithMinimumTieredPackageWithMinimumConfigTier + ) + : base(tieredPackageWithMinimumTieredPackageWithMinimumConfigTier) { } + + public TieredPackageWithMinimumTieredPackageWithMinimumConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageWithMinimumTieredPackageWithMinimumConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredPackageWithMinimumTieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumTieredPackageWithMinimumConfigTierFromRaw + : IFromRawJson +{ + /// + public TieredPackageWithMinimumTieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredPackageWithMinimumTieredPackageWithMinimumConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PackageWithAllocation : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required PackageWithAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for package_with_allocation pricing + /// + public required PackageWithAllocationPackageWithAllocationConfig PackageWithAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "package_with_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "package_with_allocation_config", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"package_with_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PackageWithAllocationConfig.Validate(); + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public PackageWithAllocation() + { + this.ModelType = JsonSerializer.Deserialize("\"package_with_allocation\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public PackageWithAllocation(PackageWithAllocation packageWithAllocation) + : base(packageWithAllocation) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public PackageWithAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"package_with_allocation\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + PackageWithAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PackageWithAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageWithAllocationFromRaw : IFromRawJson +{ + /// + public PackageWithAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PackageWithAllocation.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PackageWithAllocationBillingModeConverter))] +public enum PackageWithAllocationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class PackageWithAllocationBillingModeConverter + : JsonConverter +{ + public override PackageWithAllocationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => PackageWithAllocationBillingMode.InAdvance, + "in_arrear" => PackageWithAllocationBillingMode.InArrear, + _ => (PackageWithAllocationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageWithAllocationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageWithAllocationBillingMode.InAdvance => "in_advance", + PackageWithAllocationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PackageWithAllocationCadenceConverter))] +public enum PackageWithAllocationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class PackageWithAllocationCadenceConverter : JsonConverter +{ + public override PackageWithAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => PackageWithAllocationCadence.OneTime, + "monthly" => PackageWithAllocationCadence.Monthly, + "quarterly" => PackageWithAllocationCadence.Quarterly, + "semi_annual" => PackageWithAllocationCadence.SemiAnnual, + "annual" => PackageWithAllocationCadence.Annual, + "custom" => PackageWithAllocationCadence.Custom, + _ => (PackageWithAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageWithAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageWithAllocationCadence.OneTime => "one_time", + PackageWithAllocationCadence.Monthly => "monthly", + PackageWithAllocationCadence.Quarterly => "quarterly", + PackageWithAllocationCadence.SemiAnnual => "semi_annual", + PackageWithAllocationCadence.Annual => "annual", + PackageWithAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PackageWithAllocationCompositePriceFilter, + PackageWithAllocationCompositePriceFilterFromRaw + >) +)] +public sealed record class PackageWithAllocationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PackageWithAllocationCompositePriceFilter() { } + + public PackageWithAllocationCompositePriceFilter( + PackageWithAllocationCompositePriceFilter packageWithAllocationCompositePriceFilter + ) + : base(packageWithAllocationCompositePriceFilter) { } + + public PackageWithAllocationCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PackageWithAllocationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PackageWithAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageWithAllocationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public PackageWithAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PackageWithAllocationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PackageWithAllocationCompositePriceFilterFieldConverter))] +public enum PackageWithAllocationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PackageWithAllocationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override PackageWithAllocationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PackageWithAllocationCompositePriceFilterField.PriceID, + "item_id" => PackageWithAllocationCompositePriceFilterField.ItemID, + "price_type" => PackageWithAllocationCompositePriceFilterField.PriceType, + "currency" => PackageWithAllocationCompositePriceFilterField.Currency, + "pricing_unit_id" => PackageWithAllocationCompositePriceFilterField.PricingUnitID, + _ => (PackageWithAllocationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageWithAllocationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageWithAllocationCompositePriceFilterField.PriceID => "price_id", + PackageWithAllocationCompositePriceFilterField.ItemID => "item_id", + PackageWithAllocationCompositePriceFilterField.PriceType => "price_type", + PackageWithAllocationCompositePriceFilterField.Currency => "currency", + PackageWithAllocationCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PackageWithAllocationCompositePriceFilterOperatorConverter))] +public enum PackageWithAllocationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class PackageWithAllocationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override PackageWithAllocationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PackageWithAllocationCompositePriceFilterOperator.Includes, + "excludes" => PackageWithAllocationCompositePriceFilterOperator.Excludes, + _ => (PackageWithAllocationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageWithAllocationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageWithAllocationCompositePriceFilterOperator.Includes => "includes", + PackageWithAllocationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PackageWithAllocationConversionRateConfigConverter))] +public record class PackageWithAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PackageWithAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PackageWithAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PackageWithAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PackageWithAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PackageWithAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator PackageWithAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PackageWithAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PackageWithAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PackageWithAllocationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PackageWithAllocationConversionRateConfigConverter + : JsonConverter +{ + public override PackageWithAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PackageWithAllocationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PackageWithAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for package_with_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PackageWithAllocationPackageWithAllocationConfig, + PackageWithAllocationPackageWithAllocationConfigFromRaw + >) +)] +public sealed record class PackageWithAllocationPackageWithAllocationConfig : JsonModel +{ + /// + /// Usage allocation + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// Price per package + /// + public required string PackageAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_amount"); } + init { JsonModel.Set(this._rawData, "package_amount", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.PackageAmount; + _ = this.PackageSize; + } + + public PackageWithAllocationPackageWithAllocationConfig() { } + + public PackageWithAllocationPackageWithAllocationConfig( + PackageWithAllocationPackageWithAllocationConfig packageWithAllocationPackageWithAllocationConfig + ) + : base(packageWithAllocationPackageWithAllocationConfig) { } + + public PackageWithAllocationPackageWithAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PackageWithAllocationPackageWithAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PackageWithAllocationPackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageWithAllocationPackageWithAllocationConfigFromRaw + : IFromRawJson +{ + /// + public PackageWithAllocationPackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PackageWithAllocationPackageWithAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PackageWithAllocationPriceTypeConverter))] +public enum PackageWithAllocationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class PackageWithAllocationPriceTypeConverter : JsonConverter +{ + public override PackageWithAllocationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => PackageWithAllocationPriceType.UsagePrice, + "fixed_price" => PackageWithAllocationPriceType.FixedPrice, + "composite_price" => PackageWithAllocationPriceType.CompositePrice, + _ => (PackageWithAllocationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PackageWithAllocationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PackageWithAllocationPriceType.UsagePrice => "usage_price", + PackageWithAllocationPriceType.FixedPrice => "fixed_price", + PackageWithAllocationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UnitWithPercent : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required UnitWithPercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for unit_with_percent pricing + /// + public required UnitWithPercentUnitWithPercentConfig UnitWithPercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_percent_config" + ); + } + init { JsonModel.Set(this._rawData, "unit_with_percent_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"unit_with_percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.UnitWithPercentConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public UnitWithPercent() + { + this.ModelType = JsonSerializer.Deserialize("\"unit_with_percent\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public UnitWithPercent(UnitWithPercent unitWithPercent) + : base(unitWithPercent) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public UnitWithPercent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"unit_with_percent\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + UnitWithPercent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithPercent FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithPercentFromRaw : IFromRawJson +{ + /// + public UnitWithPercent FromRawUnchecked(IReadOnlyDictionary rawData) => + UnitWithPercent.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(UnitWithPercentBillingModeConverter))] +public enum UnitWithPercentBillingMode +{ + InAdvance, + InArrear, +} + +sealed class UnitWithPercentBillingModeConverter : JsonConverter +{ + public override UnitWithPercentBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => UnitWithPercentBillingMode.InAdvance, + "in_arrear" => UnitWithPercentBillingMode.InArrear, + _ => (UnitWithPercentBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithPercentBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithPercentBillingMode.InAdvance => "in_advance", + UnitWithPercentBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(UnitWithPercentCadenceConverter))] +public enum UnitWithPercentCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class UnitWithPercentCadenceConverter : JsonConverter +{ + public override UnitWithPercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => UnitWithPercentCadence.OneTime, + "monthly" => UnitWithPercentCadence.Monthly, + "quarterly" => UnitWithPercentCadence.Quarterly, + "semi_annual" => UnitWithPercentCadence.SemiAnnual, + "annual" => UnitWithPercentCadence.Annual, + "custom" => UnitWithPercentCadence.Custom, + _ => (UnitWithPercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithPercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithPercentCadence.OneTime => "one_time", + UnitWithPercentCadence.Monthly => "monthly", + UnitWithPercentCadence.Quarterly => "quarterly", + UnitWithPercentCadence.SemiAnnual => "semi_annual", + UnitWithPercentCadence.Annual => "annual", + UnitWithPercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + UnitWithPercentCompositePriceFilter, + UnitWithPercentCompositePriceFilterFromRaw + >) +)] +public sealed record class UnitWithPercentCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public UnitWithPercentCompositePriceFilter() { } + + public UnitWithPercentCompositePriceFilter( + UnitWithPercentCompositePriceFilter unitWithPercentCompositePriceFilter + ) + : base(unitWithPercentCompositePriceFilter) { } + + public UnitWithPercentCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithPercentCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithPercentCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithPercentCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public UnitWithPercentCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UnitWithPercentCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(UnitWithPercentCompositePriceFilterFieldConverter))] +public enum UnitWithPercentCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class UnitWithPercentCompositePriceFilterFieldConverter + : JsonConverter +{ + public override UnitWithPercentCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => UnitWithPercentCompositePriceFilterField.PriceID, + "item_id" => UnitWithPercentCompositePriceFilterField.ItemID, + "price_type" => UnitWithPercentCompositePriceFilterField.PriceType, + "currency" => UnitWithPercentCompositePriceFilterField.Currency, + "pricing_unit_id" => UnitWithPercentCompositePriceFilterField.PricingUnitID, + _ => (UnitWithPercentCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithPercentCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithPercentCompositePriceFilterField.PriceID => "price_id", + UnitWithPercentCompositePriceFilterField.ItemID => "item_id", + UnitWithPercentCompositePriceFilterField.PriceType => "price_type", + UnitWithPercentCompositePriceFilterField.Currency => "currency", + UnitWithPercentCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(UnitWithPercentCompositePriceFilterOperatorConverter))] +public enum UnitWithPercentCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class UnitWithPercentCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override UnitWithPercentCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => UnitWithPercentCompositePriceFilterOperator.Includes, + "excludes" => UnitWithPercentCompositePriceFilterOperator.Excludes, + _ => (UnitWithPercentCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithPercentCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithPercentCompositePriceFilterOperator.Includes => "includes", + UnitWithPercentCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(UnitWithPercentConversionRateConfigConverter))] +public record class UnitWithPercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public UnitWithPercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public UnitWithPercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public UnitWithPercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of UnitWithPercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of UnitWithPercentConversionRateConfig" + ), + }; + } + + public static implicit operator UnitWithPercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator UnitWithPercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of UnitWithPercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(UnitWithPercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class UnitWithPercentConversionRateConfigConverter + : JsonConverter +{ + public override UnitWithPercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new UnitWithPercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithPercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(UnitWithPercentPriceTypeConverter))] +public enum UnitWithPercentPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class UnitWithPercentPriceTypeConverter : JsonConverter +{ + public override UnitWithPercentPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => UnitWithPercentPriceType.UsagePrice, + "fixed_price" => UnitWithPercentPriceType.FixedPrice, + "composite_price" => UnitWithPercentPriceType.CompositePrice, + _ => (UnitWithPercentPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithPercentPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithPercentPriceType.UsagePrice => "usage_price", + UnitWithPercentPriceType.FixedPrice => "fixed_price", + UnitWithPercentPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + UnitWithPercentUnitWithPercentConfig, + UnitWithPercentUnitWithPercentConfigFromRaw + >) +)] +public sealed record class UnitWithPercentUnitWithPercentConfig : JsonModel +{ + /// + /// What percent, out of 100, of the calculated total to charge + /// + public required string Percent + { + get { return JsonModel.GetNotNullClass(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + _ = this.UnitAmount; + } + + public UnitWithPercentUnitWithPercentConfig() { } + + public UnitWithPercentUnitWithPercentConfig( + UnitWithPercentUnitWithPercentConfig unitWithPercentUnitWithPercentConfig + ) + : base(unitWithPercentUnitWithPercentConfig) { } + + public UnitWithPercentUnitWithPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithPercentUnitWithPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithPercentUnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithPercentUnitWithPercentConfigFromRaw + : IFromRawJson +{ + /// + public UnitWithPercentUnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UnitWithPercentUnitWithPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MatrixWithAllocation : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required MatrixWithAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + /// + /// Configuration for matrix_with_allocation pricing + /// + public required MatrixWithAllocationConfig MatrixWithAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "matrix_with_allocation_config", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.MatrixWithAllocationConfig.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"matrix_with_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MatrixWithAllocation() + { + this.ModelType = JsonSerializer.Deserialize("\"matrix_with_allocation\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MatrixWithAllocation(MatrixWithAllocation matrixWithAllocation) + : base(matrixWithAllocation) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MatrixWithAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"matrix_with_allocation\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + MatrixWithAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithAllocationFromRaw : IFromRawJson +{ + /// + public MatrixWithAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithAllocation.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MatrixWithAllocationBillingModeConverter))] +public enum MatrixWithAllocationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class MatrixWithAllocationBillingModeConverter + : JsonConverter +{ + public override MatrixWithAllocationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => MatrixWithAllocationBillingMode.InAdvance, + "in_arrear" => MatrixWithAllocationBillingMode.InArrear, + _ => (MatrixWithAllocationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithAllocationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithAllocationBillingMode.InAdvance => "in_advance", + MatrixWithAllocationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MatrixWithAllocationCadenceConverter))] +public enum MatrixWithAllocationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class MatrixWithAllocationCadenceConverter : JsonConverter +{ + public override MatrixWithAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => MatrixWithAllocationCadence.OneTime, + "monthly" => MatrixWithAllocationCadence.Monthly, + "quarterly" => MatrixWithAllocationCadence.Quarterly, + "semi_annual" => MatrixWithAllocationCadence.SemiAnnual, + "annual" => MatrixWithAllocationCadence.Annual, + "custom" => MatrixWithAllocationCadence.Custom, + _ => (MatrixWithAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithAllocationCadence.OneTime => "one_time", + MatrixWithAllocationCadence.Monthly => "monthly", + MatrixWithAllocationCadence.Quarterly => "quarterly", + MatrixWithAllocationCadence.SemiAnnual => "semi_annual", + MatrixWithAllocationCadence.Annual => "annual", + MatrixWithAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MatrixWithAllocationCompositePriceFilter, + MatrixWithAllocationCompositePriceFilterFromRaw + >) +)] +public sealed record class MatrixWithAllocationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MatrixWithAllocationCompositePriceFilter() { } + + public MatrixWithAllocationCompositePriceFilter( + MatrixWithAllocationCompositePriceFilter matrixWithAllocationCompositePriceFilter + ) + : base(matrixWithAllocationCompositePriceFilter) { } + + public MatrixWithAllocationCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithAllocationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithAllocationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public MatrixWithAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithAllocationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MatrixWithAllocationCompositePriceFilterFieldConverter))] +public enum MatrixWithAllocationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MatrixWithAllocationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override MatrixWithAllocationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MatrixWithAllocationCompositePriceFilterField.PriceID, + "item_id" => MatrixWithAllocationCompositePriceFilterField.ItemID, + "price_type" => MatrixWithAllocationCompositePriceFilterField.PriceType, + "currency" => MatrixWithAllocationCompositePriceFilterField.Currency, + "pricing_unit_id" => MatrixWithAllocationCompositePriceFilterField.PricingUnitID, + _ => (MatrixWithAllocationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithAllocationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithAllocationCompositePriceFilterField.PriceID => "price_id", + MatrixWithAllocationCompositePriceFilterField.ItemID => "item_id", + MatrixWithAllocationCompositePriceFilterField.PriceType => "price_type", + MatrixWithAllocationCompositePriceFilterField.Currency => "currency", + MatrixWithAllocationCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MatrixWithAllocationCompositePriceFilterOperatorConverter))] +public enum MatrixWithAllocationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class MatrixWithAllocationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override MatrixWithAllocationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MatrixWithAllocationCompositePriceFilterOperator.Includes, + "excludes" => MatrixWithAllocationCompositePriceFilterOperator.Excludes, + _ => (MatrixWithAllocationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithAllocationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithAllocationCompositePriceFilterOperator.Includes => "includes", + MatrixWithAllocationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MatrixWithAllocationConversionRateConfigConverter))] +public record class MatrixWithAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public MatrixWithAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MatrixWithAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MatrixWithAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of MatrixWithAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of MatrixWithAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator MatrixWithAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator MatrixWithAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of MatrixWithAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(MatrixWithAllocationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class MatrixWithAllocationConversionRateConfigConverter + : JsonConverter +{ + public override MatrixWithAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new MatrixWithAllocationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(MatrixWithAllocationPriceTypeConverter))] +public enum MatrixWithAllocationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class MatrixWithAllocationPriceTypeConverter : JsonConverter +{ + public override MatrixWithAllocationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => MatrixWithAllocationPriceType.UsagePrice, + "fixed_price" => MatrixWithAllocationPriceType.FixedPrice, + "composite_price" => MatrixWithAllocationPriceType.CompositePrice, + _ => (MatrixWithAllocationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithAllocationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithAllocationPriceType.UsagePrice => "usage_price", + MatrixWithAllocationPriceType.FixedPrice => "fixed_price", + MatrixWithAllocationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredWithProration : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required TieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required TieredWithProrationTieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.TieredWithProrationConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredWithProration(TieredWithProration tieredWithProration) + : base(tieredWithProration) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public TieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + TieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationFromRaw : IFromRawJson +{ + /// + public TieredWithProration FromRawUnchecked(IReadOnlyDictionary rawData) => + TieredWithProration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TieredWithProrationBillingModeConverter))] +public enum TieredWithProrationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class TieredWithProrationBillingModeConverter : JsonConverter +{ + public override TieredWithProrationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => TieredWithProrationBillingMode.InAdvance, + "in_arrear" => TieredWithProrationBillingMode.InArrear, + _ => (TieredWithProrationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithProrationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithProrationBillingMode.InAdvance => "in_advance", + TieredWithProrationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredWithProrationCadenceConverter))] +public enum TieredWithProrationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class TieredWithProrationCadenceConverter : JsonConverter +{ + public override TieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => TieredWithProrationCadence.OneTime, + "monthly" => TieredWithProrationCadence.Monthly, + "quarterly" => TieredWithProrationCadence.Quarterly, + "semi_annual" => TieredWithProrationCadence.SemiAnnual, + "annual" => TieredWithProrationCadence.Annual, + "custom" => TieredWithProrationCadence.Custom, + _ => (TieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithProrationCadence.OneTime => "one_time", + TieredWithProrationCadence.Monthly => "monthly", + TieredWithProrationCadence.Quarterly => "quarterly", + TieredWithProrationCadence.SemiAnnual => "semi_annual", + TieredWithProrationCadence.Annual => "annual", + TieredWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + TieredWithProrationCompositePriceFilter, + TieredWithProrationCompositePriceFilterFromRaw + >) +)] +public sealed record class TieredWithProrationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public TieredWithProrationCompositePriceFilter() { } + + public TieredWithProrationCompositePriceFilter( + TieredWithProrationCompositePriceFilter tieredWithProrationCompositePriceFilter + ) + : base(tieredWithProrationCompositePriceFilter) { } + + public TieredWithProrationCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithProrationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public TieredWithProrationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithProrationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(TieredWithProrationCompositePriceFilterFieldConverter))] +public enum TieredWithProrationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class TieredWithProrationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override TieredWithProrationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => TieredWithProrationCompositePriceFilterField.PriceID, + "item_id" => TieredWithProrationCompositePriceFilterField.ItemID, + "price_type" => TieredWithProrationCompositePriceFilterField.PriceType, + "currency" => TieredWithProrationCompositePriceFilterField.Currency, + "pricing_unit_id" => TieredWithProrationCompositePriceFilterField.PricingUnitID, + _ => (TieredWithProrationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithProrationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithProrationCompositePriceFilterField.PriceID => "price_id", + TieredWithProrationCompositePriceFilterField.ItemID => "item_id", + TieredWithProrationCompositePriceFilterField.PriceType => "price_type", + TieredWithProrationCompositePriceFilterField.Currency => "currency", + TieredWithProrationCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(TieredWithProrationCompositePriceFilterOperatorConverter))] +public enum TieredWithProrationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class TieredWithProrationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override TieredWithProrationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => TieredWithProrationCompositePriceFilterOperator.Includes, + "excludes" => TieredWithProrationCompositePriceFilterOperator.Excludes, + _ => (TieredWithProrationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithProrationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithProrationCompositePriceFilterOperator.Includes => "includes", + TieredWithProrationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(TieredWithProrationConversionRateConfigConverter))] +public record class TieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(TieredWithProrationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override TieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new TieredWithProrationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(TieredWithProrationPriceTypeConverter))] +public enum TieredWithProrationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class TieredWithProrationPriceTypeConverter : JsonConverter +{ + public override TieredWithProrationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => TieredWithProrationPriceType.UsagePrice, + "fixed_price" => TieredWithProrationPriceType.FixedPrice, + "composite_price" => TieredWithProrationPriceType.CompositePrice, + _ => (TieredWithProrationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TieredWithProrationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TieredWithProrationPriceType.UsagePrice => "usage_price", + TieredWithProrationPriceType.FixedPrice => "fixed_price", + TieredWithProrationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredWithProrationTieredWithProrationConfig, + TieredWithProrationTieredWithProrationConfigFromRaw + >) +)] +public sealed record class TieredWithProrationTieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredWithProrationTieredWithProrationConfig() { } + + public TieredWithProrationTieredWithProrationConfig( + TieredWithProrationTieredWithProrationConfig tieredWithProrationTieredWithProrationConfig + ) + : base(tieredWithProrationTieredWithProrationConfig) { } + + public TieredWithProrationTieredWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationTieredWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithProrationTieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithProrationTieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public TieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithProrationTieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + TieredWithProrationTieredWithProrationConfigTier, + TieredWithProrationTieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class TieredWithProrationTieredWithProrationConfigTier : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithProrationTieredWithProrationConfigTier() { } + + public TieredWithProrationTieredWithProrationConfigTier( + TieredWithProrationTieredWithProrationConfigTier tieredWithProrationTieredWithProrationConfigTier + ) + : base(tieredWithProrationTieredWithProrationConfigTier) { } + + public TieredWithProrationTieredWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationTieredWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationTieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public TieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TieredWithProrationTieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UnitWithProration : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required UnitWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for unit_with_proration pricing + /// + public required UnitWithProrationUnitWithProrationConfig UnitWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "unit_with_proration_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"unit_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.UnitWithProrationConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public UnitWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"unit_with_proration\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public UnitWithProration(UnitWithProration unitWithProration) + : base(unitWithProration) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public UnitWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"unit_with_proration\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + UnitWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithProrationFromRaw : IFromRawJson +{ + /// + public UnitWithProration FromRawUnchecked(IReadOnlyDictionary rawData) => + UnitWithProration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(UnitWithProrationBillingModeConverter))] +public enum UnitWithProrationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class UnitWithProrationBillingModeConverter : JsonConverter +{ + public override UnitWithProrationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => UnitWithProrationBillingMode.InAdvance, + "in_arrear" => UnitWithProrationBillingMode.InArrear, + _ => (UnitWithProrationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithProrationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithProrationBillingMode.InAdvance => "in_advance", + UnitWithProrationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(UnitWithProrationCadenceConverter))] +public enum UnitWithProrationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class UnitWithProrationCadenceConverter : JsonConverter +{ + public override UnitWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => UnitWithProrationCadence.OneTime, + "monthly" => UnitWithProrationCadence.Monthly, + "quarterly" => UnitWithProrationCadence.Quarterly, + "semi_annual" => UnitWithProrationCadence.SemiAnnual, + "annual" => UnitWithProrationCadence.Annual, + "custom" => UnitWithProrationCadence.Custom, + _ => (UnitWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithProrationCadence.OneTime => "one_time", + UnitWithProrationCadence.Monthly => "monthly", + UnitWithProrationCadence.Quarterly => "quarterly", + UnitWithProrationCadence.SemiAnnual => "semi_annual", + UnitWithProrationCadence.Annual => "annual", + UnitWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + UnitWithProrationCompositePriceFilter, + UnitWithProrationCompositePriceFilterFromRaw + >) +)] +public sealed record class UnitWithProrationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public UnitWithProrationCompositePriceFilter() { } + + public UnitWithProrationCompositePriceFilter( + UnitWithProrationCompositePriceFilter unitWithProrationCompositePriceFilter + ) + : base(unitWithProrationCompositePriceFilter) { } + + public UnitWithProrationCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithProrationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithProrationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithProrationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public UnitWithProrationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UnitWithProrationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(UnitWithProrationCompositePriceFilterFieldConverter))] +public enum UnitWithProrationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class UnitWithProrationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override UnitWithProrationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => UnitWithProrationCompositePriceFilterField.PriceID, + "item_id" => UnitWithProrationCompositePriceFilterField.ItemID, + "price_type" => UnitWithProrationCompositePriceFilterField.PriceType, + "currency" => UnitWithProrationCompositePriceFilterField.Currency, + "pricing_unit_id" => UnitWithProrationCompositePriceFilterField.PricingUnitID, + _ => (UnitWithProrationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithProrationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithProrationCompositePriceFilterField.PriceID => "price_id", + UnitWithProrationCompositePriceFilterField.ItemID => "item_id", + UnitWithProrationCompositePriceFilterField.PriceType => "price_type", + UnitWithProrationCompositePriceFilterField.Currency => "currency", + UnitWithProrationCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(UnitWithProrationCompositePriceFilterOperatorConverter))] +public enum UnitWithProrationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class UnitWithProrationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override UnitWithProrationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => UnitWithProrationCompositePriceFilterOperator.Includes, + "excludes" => UnitWithProrationCompositePriceFilterOperator.Excludes, + _ => (UnitWithProrationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithProrationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithProrationCompositePriceFilterOperator.Includes => "includes", + UnitWithProrationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(UnitWithProrationConversionRateConfigConverter))] +public record class UnitWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public UnitWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public UnitWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public UnitWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of UnitWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of UnitWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator UnitWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator UnitWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of UnitWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(UnitWithProrationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class UnitWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override UnitWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new UnitWithProrationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(UnitWithProrationPriceTypeConverter))] +public enum UnitWithProrationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class UnitWithProrationPriceTypeConverter : JsonConverter +{ + public override UnitWithProrationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => UnitWithProrationPriceType.UsagePrice, + "fixed_price" => UnitWithProrationPriceType.FixedPrice, + "composite_price" => UnitWithProrationPriceType.CompositePrice, + _ => (UnitWithProrationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnitWithProrationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnitWithProrationPriceType.UsagePrice => "usage_price", + UnitWithProrationPriceType.FixedPrice => "fixed_price", + UnitWithProrationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + UnitWithProrationUnitWithProrationConfig, + UnitWithProrationUnitWithProrationConfigFromRaw + >) +)] +public sealed record class UnitWithProrationUnitWithProrationConfig : JsonModel +{ + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + } + + public UnitWithProrationUnitWithProrationConfig() { } + + public UnitWithProrationUnitWithProrationConfig( + UnitWithProrationUnitWithProrationConfig unitWithProrationUnitWithProrationConfig + ) + : base(unitWithProrationUnitWithProrationConfig) { } + + public UnitWithProrationUnitWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithProrationUnitWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UnitWithProrationUnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public UnitWithProrationUnitWithProrationConfig(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class UnitWithProrationUnitWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public UnitWithProrationUnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UnitWithProrationUnitWithProrationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class GroupedAllocation : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required GroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// Configuration for grouped_allocation pricing + /// + public required GroupedAllocationGroupedAllocationConfig GroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_allocation_config", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.GroupedAllocationConfig.Validate(); + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize("\"grouped_allocation\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedAllocation(GroupedAllocation groupedAllocation) + : base(groupedAllocation) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"grouped_allocation\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + GroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedAllocationFromRaw : IFromRawJson +{ + /// + public GroupedAllocation FromRawUnchecked(IReadOnlyDictionary rawData) => + GroupedAllocation.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedAllocationBillingModeConverter))] +public enum GroupedAllocationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class GroupedAllocationBillingModeConverter : JsonConverter +{ + public override GroupedAllocationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => GroupedAllocationBillingMode.InAdvance, + "in_arrear" => GroupedAllocationBillingMode.InArrear, + _ => (GroupedAllocationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedAllocationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedAllocationBillingMode.InAdvance => "in_advance", + GroupedAllocationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedAllocationCadenceConverter))] +public enum GroupedAllocationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class GroupedAllocationCadenceConverter : JsonConverter +{ + public override GroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => GroupedAllocationCadence.OneTime, + "monthly" => GroupedAllocationCadence.Monthly, + "quarterly" => GroupedAllocationCadence.Quarterly, + "semi_annual" => GroupedAllocationCadence.SemiAnnual, + "annual" => GroupedAllocationCadence.Annual, + "custom" => GroupedAllocationCadence.Custom, + _ => (GroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedAllocationCadence.OneTime => "one_time", + GroupedAllocationCadence.Monthly => "monthly", + GroupedAllocationCadence.Quarterly => "quarterly", + GroupedAllocationCadence.SemiAnnual => "semi_annual", + GroupedAllocationCadence.Annual => "annual", + GroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedAllocationCompositePriceFilter, + GroupedAllocationCompositePriceFilterFromRaw + >) +)] +public sealed record class GroupedAllocationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public GroupedAllocationCompositePriceFilter() { } + + public GroupedAllocationCompositePriceFilter( + GroupedAllocationCompositePriceFilter groupedAllocationCompositePriceFilter + ) + : base(groupedAllocationCompositePriceFilter) { } + + public GroupedAllocationCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedAllocationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedAllocationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public GroupedAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedAllocationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(GroupedAllocationCompositePriceFilterFieldConverter))] +public enum GroupedAllocationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class GroupedAllocationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override GroupedAllocationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => GroupedAllocationCompositePriceFilterField.PriceID, + "item_id" => GroupedAllocationCompositePriceFilterField.ItemID, + "price_type" => GroupedAllocationCompositePriceFilterField.PriceType, + "currency" => GroupedAllocationCompositePriceFilterField.Currency, + "pricing_unit_id" => GroupedAllocationCompositePriceFilterField.PricingUnitID, + _ => (GroupedAllocationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedAllocationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedAllocationCompositePriceFilterField.PriceID => "price_id", + GroupedAllocationCompositePriceFilterField.ItemID => "item_id", + GroupedAllocationCompositePriceFilterField.PriceType => "price_type", + GroupedAllocationCompositePriceFilterField.Currency => "currency", + GroupedAllocationCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(GroupedAllocationCompositePriceFilterOperatorConverter))] +public enum GroupedAllocationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class GroupedAllocationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override GroupedAllocationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => GroupedAllocationCompositePriceFilterOperator.Includes, + "excludes" => GroupedAllocationCompositePriceFilterOperator.Excludes, + _ => (GroupedAllocationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedAllocationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedAllocationCompositePriceFilterOperator.Includes => "includes", + GroupedAllocationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedAllocationConversionRateConfigConverter))] +public record class GroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator GroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator GroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(GroupedAllocationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override GroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new GroupedAllocationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + GroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedAllocationGroupedAllocationConfig, + GroupedAllocationGroupedAllocationConfigFromRaw + >) +)] +public sealed record class GroupedAllocationGroupedAllocationConfig : JsonModel +{ + /// + /// Usage allocation per group + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// How to determine the groups that should each be allocated some quantity + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Unit rate for post-allocation + /// + public required string OverageUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "overage_unit_rate"); } + init { JsonModel.Set(this._rawData, "overage_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.GroupingKey; + _ = this.OverageUnitRate; + } + + public GroupedAllocationGroupedAllocationConfig() { } + + public GroupedAllocationGroupedAllocationConfig( + GroupedAllocationGroupedAllocationConfig groupedAllocationGroupedAllocationConfig + ) + : base(groupedAllocationGroupedAllocationConfig) { } + + public GroupedAllocationGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedAllocationGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedAllocationGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedAllocationGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public GroupedAllocationGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedAllocationGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedAllocationPriceTypeConverter))] +public enum GroupedAllocationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class GroupedAllocationPriceTypeConverter : JsonConverter +{ + public override GroupedAllocationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => GroupedAllocationPriceType.UsagePrice, + "fixed_price" => GroupedAllocationPriceType.FixedPrice, + "composite_price" => GroupedAllocationPriceType.CompositePrice, + _ => (GroupedAllocationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedAllocationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedAllocationPriceType.UsagePrice => "usage_price", + GroupedAllocationPriceType.FixedPrice => "fixed_price", + GroupedAllocationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BulkWithProration : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + /// + /// Configuration for bulk_with_proration pricing + /// + public required BulkWithProrationBulkWithProrationConfig BulkWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_proration_config", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required BulkWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.BulkWithProrationConfig.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public BulkWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_proration\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public BulkWithProration(BulkWithProration bulkWithProration) + : base(bulkWithProration) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public BulkWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_proration\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + BulkWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithProrationFromRaw : IFromRawJson +{ + /// + public BulkWithProration FromRawUnchecked(IReadOnlyDictionary rawData) => + BulkWithProration.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BulkWithProrationBillingModeConverter))] +public enum BulkWithProrationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class BulkWithProrationBillingModeConverter : JsonConverter +{ + public override BulkWithProrationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => BulkWithProrationBillingMode.InAdvance, + "in_arrear" => BulkWithProrationBillingMode.InArrear, + _ => (BulkWithProrationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithProrationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithProrationBillingMode.InAdvance => "in_advance", + BulkWithProrationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for bulk_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + BulkWithProrationBulkWithProrationConfig, + BulkWithProrationBulkWithProrationConfigFromRaw + >) +)] +public sealed record class BulkWithProrationBulkWithProrationConfig : JsonModel +{ + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithProrationBulkWithProrationConfig() { } + + public BulkWithProrationBulkWithProrationConfig( + BulkWithProrationBulkWithProrationConfig bulkWithProrationBulkWithProrationConfig + ) + : base(bulkWithProrationBulkWithProrationConfig) { } + + public BulkWithProrationBulkWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithProrationBulkWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithProrationBulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BulkWithProrationBulkWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class BulkWithProrationBulkWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public BulkWithProrationBulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithProrationBulkWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier with proration +/// +[JsonConverter( + typeof(JsonModelConverter< + BulkWithProrationBulkWithProrationConfigTier, + BulkWithProrationBulkWithProrationConfigTierFromRaw + >) +)] +public sealed record class BulkWithProrationBulkWithProrationConfigTier : JsonModel +{ + /// + /// Cost per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public BulkWithProrationBulkWithProrationConfigTier() { } + + public BulkWithProrationBulkWithProrationConfigTier( + BulkWithProrationBulkWithProrationConfigTier bulkWithProrationBulkWithProrationConfigTier + ) + : base(bulkWithProrationBulkWithProrationConfigTier) { } + + public BulkWithProrationBulkWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithProrationBulkWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithProrationBulkWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BulkWithProrationBulkWithProrationConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class BulkWithProrationBulkWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public BulkWithProrationBulkWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithProrationBulkWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(BulkWithProrationCadenceConverter))] +public enum BulkWithProrationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class BulkWithProrationCadenceConverter : JsonConverter +{ + public override BulkWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => BulkWithProrationCadence.OneTime, + "monthly" => BulkWithProrationCadence.Monthly, + "quarterly" => BulkWithProrationCadence.Quarterly, + "semi_annual" => BulkWithProrationCadence.SemiAnnual, + "annual" => BulkWithProrationCadence.Annual, + "custom" => BulkWithProrationCadence.Custom, + _ => (BulkWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithProrationCadence.OneTime => "one_time", + BulkWithProrationCadence.Monthly => "monthly", + BulkWithProrationCadence.Quarterly => "quarterly", + BulkWithProrationCadence.SemiAnnual => "semi_annual", + BulkWithProrationCadence.Annual => "annual", + BulkWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + BulkWithProrationCompositePriceFilter, + BulkWithProrationCompositePriceFilterFromRaw + >) +)] +public sealed record class BulkWithProrationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public BulkWithProrationCompositePriceFilter() { } + + public BulkWithProrationCompositePriceFilter( + BulkWithProrationCompositePriceFilter bulkWithProrationCompositePriceFilter + ) + : base(bulkWithProrationCompositePriceFilter) { } + + public BulkWithProrationCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithProrationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithProrationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithProrationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public BulkWithProrationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithProrationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(BulkWithProrationCompositePriceFilterFieldConverter))] +public enum BulkWithProrationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class BulkWithProrationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override BulkWithProrationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => BulkWithProrationCompositePriceFilterField.PriceID, + "item_id" => BulkWithProrationCompositePriceFilterField.ItemID, + "price_type" => BulkWithProrationCompositePriceFilterField.PriceType, + "currency" => BulkWithProrationCompositePriceFilterField.Currency, + "pricing_unit_id" => BulkWithProrationCompositePriceFilterField.PricingUnitID, + _ => (BulkWithProrationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithProrationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithProrationCompositePriceFilterField.PriceID => "price_id", + BulkWithProrationCompositePriceFilterField.ItemID => "item_id", + BulkWithProrationCompositePriceFilterField.PriceType => "price_type", + BulkWithProrationCompositePriceFilterField.Currency => "currency", + BulkWithProrationCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(BulkWithProrationCompositePriceFilterOperatorConverter))] +public enum BulkWithProrationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class BulkWithProrationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override BulkWithProrationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => BulkWithProrationCompositePriceFilterOperator.Includes, + "excludes" => BulkWithProrationCompositePriceFilterOperator.Excludes, + _ => (BulkWithProrationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithProrationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithProrationCompositePriceFilterOperator.Includes => "includes", + BulkWithProrationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(BulkWithProrationConversionRateConfigConverter))] +public record class BulkWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public BulkWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public BulkWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public BulkWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of BulkWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of BulkWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator BulkWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator BulkWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of BulkWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(BulkWithProrationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class BulkWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override BulkWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new BulkWithProrationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(BulkWithProrationPriceTypeConverter))] +public enum BulkWithProrationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class BulkWithProrationPriceTypeConverter : JsonConverter +{ + public override BulkWithProrationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => BulkWithProrationPriceType.UsagePrice, + "fixed_price" => BulkWithProrationPriceType.FixedPrice, + "composite_price" => BulkWithProrationPriceType.CompositePrice, + _ => (BulkWithProrationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BulkWithProrationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BulkWithProrationPriceType.UsagePrice => "usage_price", + BulkWithProrationPriceType.FixedPrice => "fixed_price", + BulkWithProrationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class GroupedWithProratedMinimum : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "billing_mode"); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required GroupedWithProratedMinimumConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// Configuration for grouped_with_prorated_minimum pricing + /// + public required GroupedWithProratedMinimumGroupedWithProratedMinimumConfig GroupedWithProratedMinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_prorated_minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_prorated_minimum_config", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.GroupedWithProratedMinimumConfig.Validate(); + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_prorated_minimum\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithProratedMinimum() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_prorated_minimum\"" + ); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithProratedMinimum(GroupedWithProratedMinimum groupedWithProratedMinimum) + : base(groupedWithProratedMinimum) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithProratedMinimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_prorated_minimum\"" + ); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + GroupedWithProratedMinimum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithProratedMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithProratedMinimumFromRaw : IFromRawJson +{ + /// + public GroupedWithProratedMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithProratedMinimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedWithProratedMinimumBillingModeConverter))] +public enum GroupedWithProratedMinimumBillingMode +{ + InAdvance, + InArrear, +} + +sealed class GroupedWithProratedMinimumBillingModeConverter + : JsonConverter +{ + public override GroupedWithProratedMinimumBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => GroupedWithProratedMinimumBillingMode.InAdvance, + "in_arrear" => GroupedWithProratedMinimumBillingMode.InArrear, + _ => (GroupedWithProratedMinimumBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithProratedMinimumBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithProratedMinimumBillingMode.InAdvance => "in_advance", + GroupedWithProratedMinimumBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedWithProratedMinimumCadenceConverter))] +public enum GroupedWithProratedMinimumCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class GroupedWithProratedMinimumCadenceConverter + : JsonConverter +{ + public override GroupedWithProratedMinimumCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => GroupedWithProratedMinimumCadence.OneTime, + "monthly" => GroupedWithProratedMinimumCadence.Monthly, + "quarterly" => GroupedWithProratedMinimumCadence.Quarterly, + "semi_annual" => GroupedWithProratedMinimumCadence.SemiAnnual, + "annual" => GroupedWithProratedMinimumCadence.Annual, + "custom" => GroupedWithProratedMinimumCadence.Custom, + _ => (GroupedWithProratedMinimumCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithProratedMinimumCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithProratedMinimumCadence.OneTime => "one_time", + GroupedWithProratedMinimumCadence.Monthly => "monthly", + GroupedWithProratedMinimumCadence.Quarterly => "quarterly", + GroupedWithProratedMinimumCadence.SemiAnnual => "semi_annual", + GroupedWithProratedMinimumCadence.Annual => "annual", + GroupedWithProratedMinimumCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithProratedMinimumCompositePriceFilter, + GroupedWithProratedMinimumCompositePriceFilterFromRaw + >) +)] +public sealed record class GroupedWithProratedMinimumCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public GroupedWithProratedMinimumCompositePriceFilter() { } + + public GroupedWithProratedMinimumCompositePriceFilter( + GroupedWithProratedMinimumCompositePriceFilter groupedWithProratedMinimumCompositePriceFilter + ) + : base(groupedWithProratedMinimumCompositePriceFilter) { } + + public GroupedWithProratedMinimumCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithProratedMinimumCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithProratedMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithProratedMinimumCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public GroupedWithProratedMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithProratedMinimumCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(GroupedWithProratedMinimumCompositePriceFilterFieldConverter))] +public enum GroupedWithProratedMinimumCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class GroupedWithProratedMinimumCompositePriceFilterFieldConverter + : JsonConverter +{ + public override GroupedWithProratedMinimumCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => GroupedWithProratedMinimumCompositePriceFilterField.PriceID, + "item_id" => GroupedWithProratedMinimumCompositePriceFilterField.ItemID, + "price_type" => GroupedWithProratedMinimumCompositePriceFilterField.PriceType, + "currency" => GroupedWithProratedMinimumCompositePriceFilterField.Currency, + "pricing_unit_id" => GroupedWithProratedMinimumCompositePriceFilterField.PricingUnitID, + _ => (GroupedWithProratedMinimumCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithProratedMinimumCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithProratedMinimumCompositePriceFilterField.PriceID => "price_id", + GroupedWithProratedMinimumCompositePriceFilterField.ItemID => "item_id", + GroupedWithProratedMinimumCompositePriceFilterField.PriceType => "price_type", + GroupedWithProratedMinimumCompositePriceFilterField.Currency => "currency", + GroupedWithProratedMinimumCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(GroupedWithProratedMinimumCompositePriceFilterOperatorConverter))] +public enum GroupedWithProratedMinimumCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class GroupedWithProratedMinimumCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override GroupedWithProratedMinimumCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => GroupedWithProratedMinimumCompositePriceFilterOperator.Includes, + "excludes" => GroupedWithProratedMinimumCompositePriceFilterOperator.Excludes, + _ => (GroupedWithProratedMinimumCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithProratedMinimumCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithProratedMinimumCompositePriceFilterOperator.Includes => "includes", + GroupedWithProratedMinimumCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedWithProratedMinimumConversionRateConfigConverter))] +public record class GroupedWithProratedMinimumConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithProratedMinimumConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithProratedMinimumConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithProratedMinimumConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithProratedMinimumConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithProratedMinimumConversionRateConfig" + ), + }; + } + + public static implicit operator GroupedWithProratedMinimumConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator GroupedWithProratedMinimumConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithProratedMinimumConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(GroupedWithProratedMinimumConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithProratedMinimumConversionRateConfigConverter + : JsonConverter +{ + public override GroupedWithProratedMinimumConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new GroupedWithProratedMinimumConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithProratedMinimumConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for grouped_with_prorated_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithProratedMinimumGroupedWithProratedMinimumConfig, + GroupedWithProratedMinimumGroupedWithProratedMinimumConfigFromRaw + >) +)] +public sealed record class GroupedWithProratedMinimumGroupedWithProratedMinimumConfig : JsonModel +{ + /// + /// How to determine the groups that should each have a minimum + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group + /// + public required string Minimum + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + /// + /// The amount to charge per unit + /// + public required string UnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rate"); } + init { JsonModel.Set(this._rawData, "unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.Minimum; + _ = this.UnitRate; + } + + public GroupedWithProratedMinimumGroupedWithProratedMinimumConfig() { } + + public GroupedWithProratedMinimumGroupedWithProratedMinimumConfig( + GroupedWithProratedMinimumGroupedWithProratedMinimumConfig groupedWithProratedMinimumGroupedWithProratedMinimumConfig + ) + : base(groupedWithProratedMinimumGroupedWithProratedMinimumConfig) { } + + public GroupedWithProratedMinimumGroupedWithProratedMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithProratedMinimumGroupedWithProratedMinimumConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithProratedMinimumGroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithProratedMinimumGroupedWithProratedMinimumConfigFromRaw + : IFromRawJson +{ + /// + public GroupedWithProratedMinimumGroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithProratedMinimumGroupedWithProratedMinimumConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedWithProratedMinimumPriceTypeConverter))] +public enum GroupedWithProratedMinimumPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class GroupedWithProratedMinimumPriceTypeConverter + : JsonConverter +{ + public override GroupedWithProratedMinimumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => GroupedWithProratedMinimumPriceType.UsagePrice, + "fixed_price" => GroupedWithProratedMinimumPriceType.FixedPrice, + "composite_price" => GroupedWithProratedMinimumPriceType.CompositePrice, + _ => (GroupedWithProratedMinimumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithProratedMinimumPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithProratedMinimumPriceType.UsagePrice => "usage_price", + GroupedWithProratedMinimumPriceType.FixedPrice => "fixed_price", + GroupedWithProratedMinimumPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class GroupedWithMeteredMinimum : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required GroupedWithMeteredMinimumConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// Configuration for grouped_with_metered_minimum pricing + /// + public required GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig GroupedWithMeteredMinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_metered_minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_metered_minimum_config", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.GroupedWithMeteredMinimumConfig.Validate(); + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_metered_minimum\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithMeteredMinimum() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_metered_minimum\"" + ); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithMeteredMinimum(GroupedWithMeteredMinimum groupedWithMeteredMinimum) + : base(groupedWithMeteredMinimum) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithMeteredMinimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_metered_minimum\"" + ); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + GroupedWithMeteredMinimum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMeteredMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumFromRaw : IFromRawJson +{ + /// + public GroupedWithMeteredMinimum FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMeteredMinimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedWithMeteredMinimumBillingModeConverter))] +public enum GroupedWithMeteredMinimumBillingMode +{ + InAdvance, + InArrear, +} + +sealed class GroupedWithMeteredMinimumBillingModeConverter + : JsonConverter +{ + public override GroupedWithMeteredMinimumBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => GroupedWithMeteredMinimumBillingMode.InAdvance, + "in_arrear" => GroupedWithMeteredMinimumBillingMode.InArrear, + _ => (GroupedWithMeteredMinimumBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMeteredMinimumBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMeteredMinimumBillingMode.InAdvance => "in_advance", + GroupedWithMeteredMinimumBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedWithMeteredMinimumCadenceConverter))] +public enum GroupedWithMeteredMinimumCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class GroupedWithMeteredMinimumCadenceConverter + : JsonConverter +{ + public override GroupedWithMeteredMinimumCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => GroupedWithMeteredMinimumCadence.OneTime, + "monthly" => GroupedWithMeteredMinimumCadence.Monthly, + "quarterly" => GroupedWithMeteredMinimumCadence.Quarterly, + "semi_annual" => GroupedWithMeteredMinimumCadence.SemiAnnual, + "annual" => GroupedWithMeteredMinimumCadence.Annual, + "custom" => GroupedWithMeteredMinimumCadence.Custom, + _ => (GroupedWithMeteredMinimumCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMeteredMinimumCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMeteredMinimumCadence.OneTime => "one_time", + GroupedWithMeteredMinimumCadence.Monthly => "monthly", + GroupedWithMeteredMinimumCadence.Quarterly => "quarterly", + GroupedWithMeteredMinimumCadence.SemiAnnual => "semi_annual", + GroupedWithMeteredMinimumCadence.Annual => "annual", + GroupedWithMeteredMinimumCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMeteredMinimumCompositePriceFilter, + GroupedWithMeteredMinimumCompositePriceFilterFromRaw + >) +)] +public sealed record class GroupedWithMeteredMinimumCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public GroupedWithMeteredMinimumCompositePriceFilter() { } + + public GroupedWithMeteredMinimumCompositePriceFilter( + GroupedWithMeteredMinimumCompositePriceFilter groupedWithMeteredMinimumCompositePriceFilter + ) + : base(groupedWithMeteredMinimumCompositePriceFilter) { } + + public GroupedWithMeteredMinimumCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMeteredMinimumCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMeteredMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public GroupedWithMeteredMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMeteredMinimumCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(GroupedWithMeteredMinimumCompositePriceFilterFieldConverter))] +public enum GroupedWithMeteredMinimumCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class GroupedWithMeteredMinimumCompositePriceFilterFieldConverter + : JsonConverter +{ + public override GroupedWithMeteredMinimumCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => GroupedWithMeteredMinimumCompositePriceFilterField.PriceID, + "item_id" => GroupedWithMeteredMinimumCompositePriceFilterField.ItemID, + "price_type" => GroupedWithMeteredMinimumCompositePriceFilterField.PriceType, + "currency" => GroupedWithMeteredMinimumCompositePriceFilterField.Currency, + "pricing_unit_id" => GroupedWithMeteredMinimumCompositePriceFilterField.PricingUnitID, + _ => (GroupedWithMeteredMinimumCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMeteredMinimumCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMeteredMinimumCompositePriceFilterField.PriceID => "price_id", + GroupedWithMeteredMinimumCompositePriceFilterField.ItemID => "item_id", + GroupedWithMeteredMinimumCompositePriceFilterField.PriceType => "price_type", + GroupedWithMeteredMinimumCompositePriceFilterField.Currency => "currency", + GroupedWithMeteredMinimumCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(GroupedWithMeteredMinimumCompositePriceFilterOperatorConverter))] +public enum GroupedWithMeteredMinimumCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class GroupedWithMeteredMinimumCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override GroupedWithMeteredMinimumCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes, + "excludes" => GroupedWithMeteredMinimumCompositePriceFilterOperator.Excludes, + _ => (GroupedWithMeteredMinimumCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMeteredMinimumCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMeteredMinimumCompositePriceFilterOperator.Includes => "includes", + GroupedWithMeteredMinimumCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedWithMeteredMinimumConversionRateConfigConverter))] +public record class GroupedWithMeteredMinimumConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMeteredMinimumConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMeteredMinimumConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMeteredMinimumConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMeteredMinimumConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMeteredMinimumConversionRateConfig" + ), + }; + } + + public static implicit operator GroupedWithMeteredMinimumConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator GroupedWithMeteredMinimumConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMeteredMinimumConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(GroupedWithMeteredMinimumConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMeteredMinimumConversionRateConfigConverter + : JsonConverter +{ + public override GroupedWithMeteredMinimumConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new GroupedWithMeteredMinimumConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMeteredMinimumConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for grouped_with_metered_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig, + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigFromRaw + >) +)] +public sealed record class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig : JsonModel +{ + /// + /// Used to partition the usage into groups. The minimum amount is applied to + /// each group. + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group per unit + /// + public required string MinimumUnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_unit_amount"); } + init { JsonModel.Set(this._rawData, "minimum_unit_amount", value); } + } + + /// + /// Used to determine the unit rate + /// + public required string PricingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_key"); } + init { JsonModel.Set(this._rawData, "pricing_key", value); } + } + + /// + /// Scale the unit rates by the scaling factor. + /// + public required IReadOnlyList ScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "scaling_factors"); + } + init { JsonModel.Set(this._rawData, "scaling_factors", value); } + } + + /// + /// Used to determine the unit rate scaling factor + /// + public required string ScalingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_key"); } + init { JsonModel.Set(this._rawData, "scaling_key", value); } + } + + /// + /// Apply per unit pricing to each pricing value. The minimum amount is applied + /// any unmatched usage. + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "unit_amounts"); + } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MinimumUnitAmount; + _ = this.PricingKey; + foreach (var item in this.ScalingFactors) + { + item.Validate(); + } + _ = this.ScalingKey; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig() { } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig( + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig groupedWithMeteredMinimumGroupedWithMeteredMinimumConfig + ) + : base(groupedWithMeteredMinimumGroupedWithMeteredMinimumConfig) { } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigFromRaw + : IFromRawJson +{ + /// + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor, + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactorFromRaw + >) +)] +public sealed record class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor + : JsonModel +{ + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Scaling value + /// + public required string ScalingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_value"); } + init { JsonModel.Set(this._rawData, "scaling_value", value); } + } + + /// + public override void Validate() + { + _ = this.ScalingFactor; + _ = this.ScalingValue; + } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor() { } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor( + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor groupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor + ) + : base(groupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor) { } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactorFromRaw + : IFromRawJson +{ + /// + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigScalingFactor.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a unit amount +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount, + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmountFromRaw + >) +)] +public sealed record class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount + : JsonModel +{ + /// + /// Pricing value + /// + public required string PricingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_value"); } + init { JsonModel.Set(this._rawData, "pricing_value", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.PricingValue; + _ = this.UnitAmount; + } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount() { } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount( + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount groupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount + ) + : base(groupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount) { } + + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmountFromRaw + : IFromRawJson +{ + /// + public GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + GroupedWithMeteredMinimumGroupedWithMeteredMinimumConfigUnitAmount.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(GroupedWithMeteredMinimumPriceTypeConverter))] +public enum GroupedWithMeteredMinimumPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class GroupedWithMeteredMinimumPriceTypeConverter + : JsonConverter +{ + public override GroupedWithMeteredMinimumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => GroupedWithMeteredMinimumPriceType.UsagePrice, + "fixed_price" => GroupedWithMeteredMinimumPriceType.FixedPrice, + "composite_price" => GroupedWithMeteredMinimumPriceType.CompositePrice, + _ => (GroupedWithMeteredMinimumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMeteredMinimumPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMeteredMinimumPriceType.UsagePrice => "usage_price", + GroupedWithMeteredMinimumPriceType.FixedPrice => "fixed_price", + GroupedWithMeteredMinimumPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class GroupedWithMinMaxThresholds : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "billing_mode"); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "composite_price_filters"); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required GroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required GroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.GroupedWithMinMaxThresholdsConfig.Validate(); + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithMinMaxThresholds(GroupedWithMinMaxThresholds groupedWithMinMaxThresholds) + : base(groupedWithMinMaxThresholds) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + GroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsFromRaw : IFromRawJson +{ + /// + public GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedWithMinMaxThresholdsBillingModeConverter))] +public enum GroupedWithMinMaxThresholdsBillingMode +{ + InAdvance, + InArrear, +} + +sealed class GroupedWithMinMaxThresholdsBillingModeConverter + : JsonConverter +{ + public override GroupedWithMinMaxThresholdsBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => GroupedWithMinMaxThresholdsBillingMode.InAdvance, + "in_arrear" => GroupedWithMinMaxThresholdsBillingMode.InArrear, + _ => (GroupedWithMinMaxThresholdsBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMinMaxThresholdsBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMinMaxThresholdsBillingMode.InAdvance => "in_advance", + GroupedWithMinMaxThresholdsBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedWithMinMaxThresholdsCadenceConverter))] +public enum GroupedWithMinMaxThresholdsCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class GroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override GroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => GroupedWithMinMaxThresholdsCadence.OneTime, + "monthly" => GroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => GroupedWithMinMaxThresholdsCadence.Quarterly, + "semi_annual" => GroupedWithMinMaxThresholdsCadence.SemiAnnual, + "annual" => GroupedWithMinMaxThresholdsCadence.Annual, + "custom" => GroupedWithMinMaxThresholdsCadence.Custom, + _ => (GroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + GroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + GroupedWithMinMaxThresholdsCadence.Quarterly => "quarterly", + GroupedWithMinMaxThresholdsCadence.SemiAnnual => "semi_annual", + GroupedWithMinMaxThresholdsCadence.Annual => "annual", + GroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMinMaxThresholdsCompositePriceFilter, + GroupedWithMinMaxThresholdsCompositePriceFilterFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum< + string, + GroupedWithMinMaxThresholdsCompositePriceFilterOperator + > Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public GroupedWithMinMaxThresholdsCompositePriceFilter() { } + + public GroupedWithMinMaxThresholdsCompositePriceFilter( + GroupedWithMinMaxThresholdsCompositePriceFilter groupedWithMinMaxThresholdsCompositePriceFilter + ) + : base(groupedWithMinMaxThresholdsCompositePriceFilter) { } + + public GroupedWithMinMaxThresholdsCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMinMaxThresholdsCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public GroupedWithMinMaxThresholdsCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMinMaxThresholdsCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(GroupedWithMinMaxThresholdsCompositePriceFilterFieldConverter))] +public enum GroupedWithMinMaxThresholdsCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class GroupedWithMinMaxThresholdsCompositePriceFilterFieldConverter + : JsonConverter +{ + public override GroupedWithMinMaxThresholdsCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID, + "item_id" => GroupedWithMinMaxThresholdsCompositePriceFilterField.ItemID, + "price_type" => GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceType, + "currency" => GroupedWithMinMaxThresholdsCompositePriceFilterField.Currency, + "pricing_unit_id" => GroupedWithMinMaxThresholdsCompositePriceFilterField.PricingUnitID, + _ => (GroupedWithMinMaxThresholdsCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMinMaxThresholdsCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceID => "price_id", + GroupedWithMinMaxThresholdsCompositePriceFilterField.ItemID => "item_id", + GroupedWithMinMaxThresholdsCompositePriceFilterField.PriceType => "price_type", + GroupedWithMinMaxThresholdsCompositePriceFilterField.Currency => "currency", + GroupedWithMinMaxThresholdsCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(GroupedWithMinMaxThresholdsCompositePriceFilterOperatorConverter))] +public enum GroupedWithMinMaxThresholdsCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class GroupedWithMinMaxThresholdsCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override GroupedWithMinMaxThresholdsCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes, + "excludes" => GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Excludes, + _ => (GroupedWithMinMaxThresholdsCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMinMaxThresholdsCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Includes => "includes", + GroupedWithMinMaxThresholdsCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedWithMinMaxThresholdsConversionRateConfigConverter))] +public record class GroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(GroupedWithMinMaxThresholdsConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override GroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new GroupedWithMinMaxThresholdsConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedWithMinMaxThresholdsConfig, + GroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsConfig : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public GroupedWithMinMaxThresholdsConfig() { } + + public GroupedWithMinMaxThresholdsConfig( + GroupedWithMinMaxThresholdsConfig groupedWithMinMaxThresholdsConfig + ) + : base(groupedWithMinMaxThresholdsConfig) { } + + public GroupedWithMinMaxThresholdsConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsConfigFromRaw : IFromRawJson +{ + /// + public GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedWithMinMaxThresholdsConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedWithMinMaxThresholdsPriceTypeConverter))] +public enum GroupedWithMinMaxThresholdsPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class GroupedWithMinMaxThresholdsPriceTypeConverter + : JsonConverter +{ + public override GroupedWithMinMaxThresholdsPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => GroupedWithMinMaxThresholdsPriceType.UsagePrice, + "fixed_price" => GroupedWithMinMaxThresholdsPriceType.FixedPrice, + "composite_price" => GroupedWithMinMaxThresholdsPriceType.CompositePrice, + _ => (GroupedWithMinMaxThresholdsPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedWithMinMaxThresholdsPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedWithMinMaxThresholdsPriceType.UsagePrice => "usage_price", + GroupedWithMinMaxThresholdsPriceType.FixedPrice => "fixed_price", + GroupedWithMinMaxThresholdsPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MatrixWithDisplayName : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required MatrixWithDisplayNameConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + /// + /// Configuration for matrix_with_display_name pricing + /// + public required MatrixWithDisplayNameMatrixWithDisplayNameConfig MatrixWithDisplayNameConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_display_name_config" + ); + } + init { JsonModel.Set(this._rawData, "matrix_with_display_name_config", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.MatrixWithDisplayNameConfig.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"matrix_with_display_name\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MatrixWithDisplayName() + { + this.ModelType = JsonSerializer.Deserialize("\"matrix_with_display_name\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MatrixWithDisplayName(MatrixWithDisplayName matrixWithDisplayName) + : base(matrixWithDisplayName) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MatrixWithDisplayName(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"matrix_with_display_name\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + MatrixWithDisplayName(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithDisplayName FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameFromRaw : IFromRawJson +{ + /// + public MatrixWithDisplayName FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithDisplayName.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MatrixWithDisplayNameBillingModeConverter))] +public enum MatrixWithDisplayNameBillingMode +{ + InAdvance, + InArrear, +} + +sealed class MatrixWithDisplayNameBillingModeConverter + : JsonConverter +{ + public override MatrixWithDisplayNameBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => MatrixWithDisplayNameBillingMode.InAdvance, + "in_arrear" => MatrixWithDisplayNameBillingMode.InArrear, + _ => (MatrixWithDisplayNameBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithDisplayNameBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithDisplayNameBillingMode.InAdvance => "in_advance", + MatrixWithDisplayNameBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MatrixWithDisplayNameCadenceConverter))] +public enum MatrixWithDisplayNameCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class MatrixWithDisplayNameCadenceConverter : JsonConverter +{ + public override MatrixWithDisplayNameCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => MatrixWithDisplayNameCadence.OneTime, + "monthly" => MatrixWithDisplayNameCadence.Monthly, + "quarterly" => MatrixWithDisplayNameCadence.Quarterly, + "semi_annual" => MatrixWithDisplayNameCadence.SemiAnnual, + "annual" => MatrixWithDisplayNameCadence.Annual, + "custom" => MatrixWithDisplayNameCadence.Custom, + _ => (MatrixWithDisplayNameCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithDisplayNameCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithDisplayNameCadence.OneTime => "one_time", + MatrixWithDisplayNameCadence.Monthly => "monthly", + MatrixWithDisplayNameCadence.Quarterly => "quarterly", + MatrixWithDisplayNameCadence.SemiAnnual => "semi_annual", + MatrixWithDisplayNameCadence.Annual => "annual", + MatrixWithDisplayNameCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MatrixWithDisplayNameCompositePriceFilter, + MatrixWithDisplayNameCompositePriceFilterFromRaw + >) +)] +public sealed record class MatrixWithDisplayNameCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MatrixWithDisplayNameCompositePriceFilter() { } + + public MatrixWithDisplayNameCompositePriceFilter( + MatrixWithDisplayNameCompositePriceFilter matrixWithDisplayNameCompositePriceFilter + ) + : base(matrixWithDisplayNameCompositePriceFilter) { } + + public MatrixWithDisplayNameCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithDisplayNameCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithDisplayNameCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public MatrixWithDisplayNameCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithDisplayNameCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MatrixWithDisplayNameCompositePriceFilterFieldConverter))] +public enum MatrixWithDisplayNameCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MatrixWithDisplayNameCompositePriceFilterFieldConverter + : JsonConverter +{ + public override MatrixWithDisplayNameCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MatrixWithDisplayNameCompositePriceFilterField.PriceID, + "item_id" => MatrixWithDisplayNameCompositePriceFilterField.ItemID, + "price_type" => MatrixWithDisplayNameCompositePriceFilterField.PriceType, + "currency" => MatrixWithDisplayNameCompositePriceFilterField.Currency, + "pricing_unit_id" => MatrixWithDisplayNameCompositePriceFilterField.PricingUnitID, + _ => (MatrixWithDisplayNameCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithDisplayNameCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithDisplayNameCompositePriceFilterField.PriceID => "price_id", + MatrixWithDisplayNameCompositePriceFilterField.ItemID => "item_id", + MatrixWithDisplayNameCompositePriceFilterField.PriceType => "price_type", + MatrixWithDisplayNameCompositePriceFilterField.Currency => "currency", + MatrixWithDisplayNameCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MatrixWithDisplayNameCompositePriceFilterOperatorConverter))] +public enum MatrixWithDisplayNameCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class MatrixWithDisplayNameCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override MatrixWithDisplayNameCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MatrixWithDisplayNameCompositePriceFilterOperator.Includes, + "excludes" => MatrixWithDisplayNameCompositePriceFilterOperator.Excludes, + _ => (MatrixWithDisplayNameCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithDisplayNameCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithDisplayNameCompositePriceFilterOperator.Includes => "includes", + MatrixWithDisplayNameCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MatrixWithDisplayNameConversionRateConfigConverter))] +public record class MatrixWithDisplayNameConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public MatrixWithDisplayNameConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MatrixWithDisplayNameConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MatrixWithDisplayNameConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of MatrixWithDisplayNameConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of MatrixWithDisplayNameConversionRateConfig" + ), + }; + } + + public static implicit operator MatrixWithDisplayNameConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator MatrixWithDisplayNameConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of MatrixWithDisplayNameConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(MatrixWithDisplayNameConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class MatrixWithDisplayNameConversionRateConfigConverter + : JsonConverter +{ + public override MatrixWithDisplayNameConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new MatrixWithDisplayNameConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithDisplayNameConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for matrix_with_display_name pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + MatrixWithDisplayNameMatrixWithDisplayNameConfig, + MatrixWithDisplayNameMatrixWithDisplayNameConfigFromRaw + >) +)] +public sealed record class MatrixWithDisplayNameMatrixWithDisplayNameConfig : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string Dimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension"); } + init { JsonModel.Set(this._rawData, "dimension", value); } + } + + /// + /// Apply per unit pricing to each dimension value + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "unit_amounts"); + } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } + } + + /// + public override void Validate() + { + _ = this.Dimension; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public MatrixWithDisplayNameMatrixWithDisplayNameConfig() { } + + public MatrixWithDisplayNameMatrixWithDisplayNameConfig( + MatrixWithDisplayNameMatrixWithDisplayNameConfig matrixWithDisplayNameMatrixWithDisplayNameConfig + ) + : base(matrixWithDisplayNameMatrixWithDisplayNameConfig) { } + + public MatrixWithDisplayNameMatrixWithDisplayNameConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithDisplayNameMatrixWithDisplayNameConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithDisplayNameMatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameMatrixWithDisplayNameConfigFromRaw + : IFromRawJson +{ + /// + public MatrixWithDisplayNameMatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithDisplayNameMatrixWithDisplayNameConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a unit amount item +/// +[JsonConverter( + typeof(JsonModelConverter< + MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount, + MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmountFromRaw + >) +)] +public sealed record class MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount : JsonModel +{ + /// + /// The dimension value + /// + public required string DimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension_value"); } + init { JsonModel.Set(this._rawData, "dimension_value", value); } + } + + /// + /// Display name for this dimension value + /// + public required string DisplayName + { + get { return JsonModel.GetNotNullClass(this.RawData, "display_name"); } + init { JsonModel.Set(this._rawData, "display_name", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.DimensionValue; + _ = this.DisplayName; + _ = this.UnitAmount; + } + + public MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount() { } + + public MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount( + MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount matrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount + ) + : base(matrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount) { } + + public MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmountFromRaw + : IFromRawJson +{ + /// + public MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MatrixWithDisplayNameMatrixWithDisplayNameConfigUnitAmount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MatrixWithDisplayNamePriceTypeConverter))] +public enum MatrixWithDisplayNamePriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class MatrixWithDisplayNamePriceTypeConverter : JsonConverter +{ + public override MatrixWithDisplayNamePriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => MatrixWithDisplayNamePriceType.UsagePrice, + "fixed_price" => MatrixWithDisplayNamePriceType.FixedPrice, + "composite_price" => MatrixWithDisplayNamePriceType.CompositePrice, + _ => (MatrixWithDisplayNamePriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MatrixWithDisplayNamePriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MatrixWithDisplayNamePriceType.UsagePrice => "usage_price", + MatrixWithDisplayNamePriceType.FixedPrice => "fixed_price", + MatrixWithDisplayNamePriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class GroupedTieredPackage : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required GroupedTieredPackageConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// Configuration for grouped_tiered_package pricing + /// + public required GroupedTieredPackageGroupedTieredPackageConfig GroupedTieredPackageConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_package_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_tiered_package_config", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.GroupedTieredPackageConfig.Validate(); + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_tiered_package\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedTieredPackage() + { + this.ModelType = JsonSerializer.Deserialize("\"grouped_tiered_package\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedTieredPackage(GroupedTieredPackage groupedTieredPackage) + : base(groupedTieredPackage) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public GroupedTieredPackage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"grouped_tiered_package\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + GroupedTieredPackage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredPackage FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageFromRaw : IFromRawJson +{ + /// + public GroupedTieredPackage FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredPackage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedTieredPackageBillingModeConverter))] +public enum GroupedTieredPackageBillingMode +{ + InAdvance, + InArrear, +} + +sealed class GroupedTieredPackageBillingModeConverter + : JsonConverter +{ + public override GroupedTieredPackageBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => GroupedTieredPackageBillingMode.InAdvance, + "in_arrear" => GroupedTieredPackageBillingMode.InArrear, + _ => (GroupedTieredPackageBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPackageBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredPackageBillingMode.InAdvance => "in_advance", + GroupedTieredPackageBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedTieredPackageCadenceConverter))] +public enum GroupedTieredPackageCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class GroupedTieredPackageCadenceConverter : JsonConverter +{ + public override GroupedTieredPackageCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => GroupedTieredPackageCadence.OneTime, + "monthly" => GroupedTieredPackageCadence.Monthly, + "quarterly" => GroupedTieredPackageCadence.Quarterly, + "semi_annual" => GroupedTieredPackageCadence.SemiAnnual, + "annual" => GroupedTieredPackageCadence.Annual, + "custom" => GroupedTieredPackageCadence.Custom, + _ => (GroupedTieredPackageCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPackageCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredPackageCadence.OneTime => "one_time", + GroupedTieredPackageCadence.Monthly => "monthly", + GroupedTieredPackageCadence.Quarterly => "quarterly", + GroupedTieredPackageCadence.SemiAnnual => "semi_annual", + GroupedTieredPackageCadence.Annual => "annual", + GroupedTieredPackageCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredPackageCompositePriceFilter, + GroupedTieredPackageCompositePriceFilterFromRaw + >) +)] +public sealed record class GroupedTieredPackageCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public GroupedTieredPackageCompositePriceFilter() { } + + public GroupedTieredPackageCompositePriceFilter( + GroupedTieredPackageCompositePriceFilter groupedTieredPackageCompositePriceFilter + ) + : base(groupedTieredPackageCompositePriceFilter) { } + + public GroupedTieredPackageCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredPackageCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredPackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public GroupedTieredPackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredPackageCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(GroupedTieredPackageCompositePriceFilterFieldConverter))] +public enum GroupedTieredPackageCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class GroupedTieredPackageCompositePriceFilterFieldConverter + : JsonConverter +{ + public override GroupedTieredPackageCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => GroupedTieredPackageCompositePriceFilterField.PriceID, + "item_id" => GroupedTieredPackageCompositePriceFilterField.ItemID, + "price_type" => GroupedTieredPackageCompositePriceFilterField.PriceType, + "currency" => GroupedTieredPackageCompositePriceFilterField.Currency, + "pricing_unit_id" => GroupedTieredPackageCompositePriceFilterField.PricingUnitID, + _ => (GroupedTieredPackageCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPackageCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredPackageCompositePriceFilterField.PriceID => "price_id", + GroupedTieredPackageCompositePriceFilterField.ItemID => "item_id", + GroupedTieredPackageCompositePriceFilterField.PriceType => "price_type", + GroupedTieredPackageCompositePriceFilterField.Currency => "currency", + GroupedTieredPackageCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(GroupedTieredPackageCompositePriceFilterOperatorConverter))] +public enum GroupedTieredPackageCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class GroupedTieredPackageCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override GroupedTieredPackageCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => GroupedTieredPackageCompositePriceFilterOperator.Includes, + "excludes" => GroupedTieredPackageCompositePriceFilterOperator.Excludes, + _ => (GroupedTieredPackageCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPackageCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredPackageCompositePriceFilterOperator.Includes => "includes", + GroupedTieredPackageCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(GroupedTieredPackageConversionRateConfigConverter))] +public record class GroupedTieredPackageConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedTieredPackageConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedTieredPackageConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedTieredPackageConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedTieredPackageConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedTieredPackageConversionRateConfig" + ), + }; + } + + public static implicit operator GroupedTieredPackageConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator GroupedTieredPackageConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedTieredPackageConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(GroupedTieredPackageConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedTieredPackageConversionRateConfigConverter + : JsonConverter +{ + public override GroupedTieredPackageConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new GroupedTieredPackageConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPackageConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for grouped_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredPackageGroupedTieredPackageConfig, + GroupedTieredPackageGroupedTieredPackageConfigFromRaw + >) +)] +public sealed record class GroupedTieredPackageGroupedTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public GroupedTieredPackageGroupedTieredPackageConfig() { } + + public GroupedTieredPackageGroupedTieredPackageConfig( + GroupedTieredPackageGroupedTieredPackageConfig groupedTieredPackageGroupedTieredPackageConfig + ) + : base(groupedTieredPackageGroupedTieredPackageConfig) { } + + public GroupedTieredPackageGroupedTieredPackageConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredPackageGroupedTieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredPackageGroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageGroupedTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public GroupedTieredPackageGroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredPackageGroupedTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + GroupedTieredPackageGroupedTieredPackageConfigTier, + GroupedTieredPackageGroupedTieredPackageConfigTierFromRaw + >) +)] +public sealed record class GroupedTieredPackageGroupedTieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public GroupedTieredPackageGroupedTieredPackageConfigTier() { } + + public GroupedTieredPackageGroupedTieredPackageConfigTier( + GroupedTieredPackageGroupedTieredPackageConfigTier groupedTieredPackageGroupedTieredPackageConfigTier + ) + : base(groupedTieredPackageGroupedTieredPackageConfigTier) { } + + public GroupedTieredPackageGroupedTieredPackageConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredPackageGroupedTieredPackageConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedTieredPackageGroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageGroupedTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public GroupedTieredPackageGroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedTieredPackageGroupedTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedTieredPackagePriceTypeConverter))] +public enum GroupedTieredPackagePriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class GroupedTieredPackagePriceTypeConverter : JsonConverter +{ + public override GroupedTieredPackagePriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => GroupedTieredPackagePriceType.UsagePrice, + "fixed_price" => GroupedTieredPackagePriceType.FixedPrice, + "composite_price" => GroupedTieredPackagePriceType.CompositePrice, + _ => (GroupedTieredPackagePriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedTieredPackagePriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedTieredPackagePriceType.UsagePrice => "usage_price", + GroupedTieredPackagePriceType.FixedPrice => "fixed_price", + GroupedTieredPackagePriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MaxGroupTieredPackage : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required MaxGroupTieredPackageConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + /// + /// Configuration for max_group_tiered_package pricing + /// + public required MaxGroupTieredPackageMaxGroupTieredPackageConfig MaxGroupTieredPackageConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "max_group_tiered_package_config" + ); + } + init { JsonModel.Set(this._rawData, "max_group_tiered_package_config", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.MaxGroupTieredPackageConfig.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"max_group_tiered_package\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MaxGroupTieredPackage() + { + this.ModelType = JsonSerializer.Deserialize("\"max_group_tiered_package\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MaxGroupTieredPackage(MaxGroupTieredPackage maxGroupTieredPackage) + : base(maxGroupTieredPackage) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public MaxGroupTieredPackage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"max_group_tiered_package\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + MaxGroupTieredPackage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaxGroupTieredPackage FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageFromRaw : IFromRawJson +{ + /// + public MaxGroupTieredPackage FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaxGroupTieredPackage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MaxGroupTieredPackageBillingModeConverter))] +public enum MaxGroupTieredPackageBillingMode +{ + InAdvance, + InArrear, +} + +sealed class MaxGroupTieredPackageBillingModeConverter + : JsonConverter +{ + public override MaxGroupTieredPackageBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => MaxGroupTieredPackageBillingMode.InAdvance, + "in_arrear" => MaxGroupTieredPackageBillingMode.InArrear, + _ => (MaxGroupTieredPackageBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaxGroupTieredPackageBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaxGroupTieredPackageBillingMode.InAdvance => "in_advance", + MaxGroupTieredPackageBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MaxGroupTieredPackageCadenceConverter))] +public enum MaxGroupTieredPackageCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class MaxGroupTieredPackageCadenceConverter : JsonConverter +{ + public override MaxGroupTieredPackageCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => MaxGroupTieredPackageCadence.OneTime, + "monthly" => MaxGroupTieredPackageCadence.Monthly, + "quarterly" => MaxGroupTieredPackageCadence.Quarterly, + "semi_annual" => MaxGroupTieredPackageCadence.SemiAnnual, + "annual" => MaxGroupTieredPackageCadence.Annual, + "custom" => MaxGroupTieredPackageCadence.Custom, + _ => (MaxGroupTieredPackageCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaxGroupTieredPackageCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaxGroupTieredPackageCadence.OneTime => "one_time", + MaxGroupTieredPackageCadence.Monthly => "monthly", + MaxGroupTieredPackageCadence.Quarterly => "quarterly", + MaxGroupTieredPackageCadence.SemiAnnual => "semi_annual", + MaxGroupTieredPackageCadence.Annual => "annual", + MaxGroupTieredPackageCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + MaxGroupTieredPackageCompositePriceFilter, + MaxGroupTieredPackageCompositePriceFilterFromRaw + >) +)] +public sealed record class MaxGroupTieredPackageCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public MaxGroupTieredPackageCompositePriceFilter() { } + + public MaxGroupTieredPackageCompositePriceFilter( + MaxGroupTieredPackageCompositePriceFilter maxGroupTieredPackageCompositePriceFilter + ) + : base(maxGroupTieredPackageCompositePriceFilter) { } + + public MaxGroupTieredPackageCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaxGroupTieredPackageCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaxGroupTieredPackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public MaxGroupTieredPackageCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaxGroupTieredPackageCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(MaxGroupTieredPackageCompositePriceFilterFieldConverter))] +public enum MaxGroupTieredPackageCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class MaxGroupTieredPackageCompositePriceFilterFieldConverter + : JsonConverter +{ + public override MaxGroupTieredPackageCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => MaxGroupTieredPackageCompositePriceFilterField.PriceID, + "item_id" => MaxGroupTieredPackageCompositePriceFilterField.ItemID, + "price_type" => MaxGroupTieredPackageCompositePriceFilterField.PriceType, + "currency" => MaxGroupTieredPackageCompositePriceFilterField.Currency, + "pricing_unit_id" => MaxGroupTieredPackageCompositePriceFilterField.PricingUnitID, + _ => (MaxGroupTieredPackageCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaxGroupTieredPackageCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaxGroupTieredPackageCompositePriceFilterField.PriceID => "price_id", + MaxGroupTieredPackageCompositePriceFilterField.ItemID => "item_id", + MaxGroupTieredPackageCompositePriceFilterField.PriceType => "price_type", + MaxGroupTieredPackageCompositePriceFilterField.Currency => "currency", + MaxGroupTieredPackageCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(MaxGroupTieredPackageCompositePriceFilterOperatorConverter))] +public enum MaxGroupTieredPackageCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class MaxGroupTieredPackageCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override MaxGroupTieredPackageCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => MaxGroupTieredPackageCompositePriceFilterOperator.Includes, + "excludes" => MaxGroupTieredPackageCompositePriceFilterOperator.Excludes, + _ => (MaxGroupTieredPackageCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaxGroupTieredPackageCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaxGroupTieredPackageCompositePriceFilterOperator.Includes => "includes", + MaxGroupTieredPackageCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(MaxGroupTieredPackageConversionRateConfigConverter))] +public record class MaxGroupTieredPackageConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public MaxGroupTieredPackageConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MaxGroupTieredPackageConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public MaxGroupTieredPackageConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of MaxGroupTieredPackageConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of MaxGroupTieredPackageConversionRateConfig" + ), + }; + } + + public static implicit operator MaxGroupTieredPackageConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator MaxGroupTieredPackageConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of MaxGroupTieredPackageConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(MaxGroupTieredPackageConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class MaxGroupTieredPackageConversionRateConfigConverter + : JsonConverter +{ + public override MaxGroupTieredPackageConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new MaxGroupTieredPackageConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + MaxGroupTieredPackageConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for max_group_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + MaxGroupTieredPackageMaxGroupTieredPackageConfig, + MaxGroupTieredPackageMaxGroupTieredPackageConfigFromRaw + >) +)] +public sealed record class MaxGroupTieredPackageMaxGroupTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering the group with the highest value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing to the largest group after grouping with the provided key. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public MaxGroupTieredPackageMaxGroupTieredPackageConfig() { } + + public MaxGroupTieredPackageMaxGroupTieredPackageConfig( + MaxGroupTieredPackageMaxGroupTieredPackageConfig maxGroupTieredPackageMaxGroupTieredPackageConfig + ) + : base(maxGroupTieredPackageMaxGroupTieredPackageConfig) { } + + public MaxGroupTieredPackageMaxGroupTieredPackageConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaxGroupTieredPackageMaxGroupTieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaxGroupTieredPackageMaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageMaxGroupTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public MaxGroupTieredPackageMaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaxGroupTieredPackageMaxGroupTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + MaxGroupTieredPackageMaxGroupTieredPackageConfigTier, + MaxGroupTieredPackageMaxGroupTieredPackageConfigTierFromRaw + >) +)] +public sealed record class MaxGroupTieredPackageMaxGroupTieredPackageConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public MaxGroupTieredPackageMaxGroupTieredPackageConfigTier() { } + + public MaxGroupTieredPackageMaxGroupTieredPackageConfigTier( + MaxGroupTieredPackageMaxGroupTieredPackageConfigTier maxGroupTieredPackageMaxGroupTieredPackageConfigTier + ) + : base(maxGroupTieredPackageMaxGroupTieredPackageConfigTier) { } + + public MaxGroupTieredPackageMaxGroupTieredPackageConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaxGroupTieredPackageMaxGroupTieredPackageConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaxGroupTieredPackageMaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageMaxGroupTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public MaxGroupTieredPackageMaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaxGroupTieredPackageMaxGroupTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MaxGroupTieredPackagePriceTypeConverter))] +public enum MaxGroupTieredPackagePriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class MaxGroupTieredPackagePriceTypeConverter : JsonConverter +{ + public override MaxGroupTieredPackagePriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => MaxGroupTieredPackagePriceType.UsagePrice, + "fixed_price" => MaxGroupTieredPackagePriceType.FixedPrice, + "composite_price" => MaxGroupTieredPackagePriceType.CompositePrice, + _ => (MaxGroupTieredPackagePriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaxGroupTieredPackagePriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaxGroupTieredPackagePriceType.UsagePrice => "usage_price", + MaxGroupTieredPackagePriceType.FixedPrice => "fixed_price", + MaxGroupTieredPackagePriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ScalableMatrixWithUnitPricing : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "billing_mode"); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "composite_price_filters"); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required ScalableMatrixWithUnitPricingConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "price_type"); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for scalable_matrix_with_unit_pricing pricing + /// + public required ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig ScalableMatrixWithUnitPricingConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_unit_pricing_config" + ); + } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_unit_pricing_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"scalable_matrix_with_unit_pricing\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.ScalableMatrixWithUnitPricingConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ScalableMatrixWithUnitPricing() + { + this.ModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_unit_pricing\"" + ); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ScalableMatrixWithUnitPricing( + ScalableMatrixWithUnitPricing scalableMatrixWithUnitPricing + ) + : base(scalableMatrixWithUnitPricing) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ScalableMatrixWithUnitPricing(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_unit_pricing\"" + ); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + ScalableMatrixWithUnitPricing(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithUnitPricing FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingFromRaw : IFromRawJson +{ + /// + public ScalableMatrixWithUnitPricing FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithUnitPricing.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ScalableMatrixWithUnitPricingBillingModeConverter))] +public enum ScalableMatrixWithUnitPricingBillingMode +{ + InAdvance, + InArrear, +} + +sealed class ScalableMatrixWithUnitPricingBillingModeConverter + : JsonConverter +{ + public override ScalableMatrixWithUnitPricingBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => ScalableMatrixWithUnitPricingBillingMode.InAdvance, + "in_arrear" => ScalableMatrixWithUnitPricingBillingMode.InArrear, + _ => (ScalableMatrixWithUnitPricingBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithUnitPricingBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithUnitPricingBillingMode.InAdvance => "in_advance", + ScalableMatrixWithUnitPricingBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ScalableMatrixWithUnitPricingCadenceConverter))] +public enum ScalableMatrixWithUnitPricingCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class ScalableMatrixWithUnitPricingCadenceConverter + : JsonConverter +{ + public override ScalableMatrixWithUnitPricingCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => ScalableMatrixWithUnitPricingCadence.OneTime, + "monthly" => ScalableMatrixWithUnitPricingCadence.Monthly, + "quarterly" => ScalableMatrixWithUnitPricingCadence.Quarterly, + "semi_annual" => ScalableMatrixWithUnitPricingCadence.SemiAnnual, + "annual" => ScalableMatrixWithUnitPricingCadence.Annual, + "custom" => ScalableMatrixWithUnitPricingCadence.Custom, + _ => (ScalableMatrixWithUnitPricingCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithUnitPricingCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithUnitPricingCadence.OneTime => "one_time", + ScalableMatrixWithUnitPricingCadence.Monthly => "monthly", + ScalableMatrixWithUnitPricingCadence.Quarterly => "quarterly", + ScalableMatrixWithUnitPricingCadence.SemiAnnual => "semi_annual", + ScalableMatrixWithUnitPricingCadence.Annual => "annual", + ScalableMatrixWithUnitPricingCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithUnitPricingCompositePriceFilter, + ScalableMatrixWithUnitPricingCompositePriceFilterFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum< + string, + ScalableMatrixWithUnitPricingCompositePriceFilterOperator + > Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public ScalableMatrixWithUnitPricingCompositePriceFilter() { } + + public ScalableMatrixWithUnitPricingCompositePriceFilter( + ScalableMatrixWithUnitPricingCompositePriceFilter scalableMatrixWithUnitPricingCompositePriceFilter + ) + : base(scalableMatrixWithUnitPricingCompositePriceFilter) { } + + public ScalableMatrixWithUnitPricingCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithUnitPricingCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithUnitPricingCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithUnitPricingCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(ScalableMatrixWithUnitPricingCompositePriceFilterFieldConverter))] +public enum ScalableMatrixWithUnitPricingCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class ScalableMatrixWithUnitPricingCompositePriceFilterFieldConverter + : JsonConverter +{ + public override ScalableMatrixWithUnitPricingCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID, + "item_id" => ScalableMatrixWithUnitPricingCompositePriceFilterField.ItemID, + "price_type" => ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceType, + "currency" => ScalableMatrixWithUnitPricingCompositePriceFilterField.Currency, + "pricing_unit_id" => + ScalableMatrixWithUnitPricingCompositePriceFilterField.PricingUnitID, + _ => (ScalableMatrixWithUnitPricingCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithUnitPricingCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceID => "price_id", + ScalableMatrixWithUnitPricingCompositePriceFilterField.ItemID => "item_id", + ScalableMatrixWithUnitPricingCompositePriceFilterField.PriceType => "price_type", + ScalableMatrixWithUnitPricingCompositePriceFilterField.Currency => "currency", + ScalableMatrixWithUnitPricingCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(ScalableMatrixWithUnitPricingCompositePriceFilterOperatorConverter))] +public enum ScalableMatrixWithUnitPricingCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class ScalableMatrixWithUnitPricingCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override ScalableMatrixWithUnitPricingCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes, + "excludes" => ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Excludes, + _ => (ScalableMatrixWithUnitPricingCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithUnitPricingCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Includes => "includes", + ScalableMatrixWithUnitPricingCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ScalableMatrixWithUnitPricingConversionRateConfigConverter))] +public record class ScalableMatrixWithUnitPricingConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ScalableMatrixWithUnitPricingConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ScalableMatrixWithUnitPricingConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ScalableMatrixWithUnitPricingConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ScalableMatrixWithUnitPricingConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ScalableMatrixWithUnitPricingConversionRateConfig" + ), + }; + } + + public static implicit operator ScalableMatrixWithUnitPricingConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ScalableMatrixWithUnitPricingConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ScalableMatrixWithUnitPricingConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ScalableMatrixWithUnitPricingConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ScalableMatrixWithUnitPricingConversionRateConfigConverter + : JsonConverter +{ + public override ScalableMatrixWithUnitPricingConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ScalableMatrixWithUnitPricingConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithUnitPricingConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(ScalableMatrixWithUnitPricingPriceTypeConverter))] +public enum ScalableMatrixWithUnitPricingPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class ScalableMatrixWithUnitPricingPriceTypeConverter + : JsonConverter +{ + public override ScalableMatrixWithUnitPricingPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => ScalableMatrixWithUnitPricingPriceType.UsagePrice, + "fixed_price" => ScalableMatrixWithUnitPricingPriceType.FixedPrice, + "composite_price" => ScalableMatrixWithUnitPricingPriceType.CompositePrice, + _ => (ScalableMatrixWithUnitPricingPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithUnitPricingPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithUnitPricingPriceType.UsagePrice => "usage_price", + ScalableMatrixWithUnitPricingPriceType.FixedPrice => "fixed_price", + ScalableMatrixWithUnitPricingPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_unit_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig, + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); + } + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } + } + + /// + /// The final unit price to rate against the output of the matrix + /// + public required string UnitPrice + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_price"); } + init { JsonModel.Set(this._rawData, "unit_price", value); } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + /// Used to determine the unit rate (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + _ = this.UnitPrice; + _ = this.Prorate; + _ = this.SecondDimension; + } + + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig() { } + + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig( + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig scalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig + ) + : base(scalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig) { } + + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor, + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor() { } + + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor scalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor + ) + : base(scalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor) + { } + + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ScalableMatrixWithUnitPricingScalableMatrixWithUnitPricingConfigMatrixScalingFactor.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricing, + ScalableMatrixWithTieredPricingFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricing : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "billing_mode"); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "composite_price_filters"); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required ScalableMatrixWithTieredPricingConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "price_type"); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// Configuration for scalable_matrix_with_tiered_pricing pricing + /// + public required ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig ScalableMatrixWithTieredPricingConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_tiered_pricing_config" + ); + } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_tiered_pricing_config", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"scalable_matrix_with_tiered_pricing\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.ScalableMatrixWithTieredPricingConfig.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ScalableMatrixWithTieredPricing() + { + this.ModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_tiered_pricing\"" + ); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ScalableMatrixWithTieredPricing( + ScalableMatrixWithTieredPricing scalableMatrixWithTieredPricing + ) + : base(scalableMatrixWithTieredPricing) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public ScalableMatrixWithTieredPricing(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"scalable_matrix_with_tiered_pricing\"" + ); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + ScalableMatrixWithTieredPricing(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithTieredPricing FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingFromRaw : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricing FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithTieredPricing.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ScalableMatrixWithTieredPricingBillingModeConverter))] +public enum ScalableMatrixWithTieredPricingBillingMode +{ + InAdvance, + InArrear, +} + +sealed class ScalableMatrixWithTieredPricingBillingModeConverter + : JsonConverter +{ + public override ScalableMatrixWithTieredPricingBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => ScalableMatrixWithTieredPricingBillingMode.InAdvance, + "in_arrear" => ScalableMatrixWithTieredPricingBillingMode.InArrear, + _ => (ScalableMatrixWithTieredPricingBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithTieredPricingBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithTieredPricingBillingMode.InAdvance => "in_advance", + ScalableMatrixWithTieredPricingBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ScalableMatrixWithTieredPricingCadenceConverter))] +public enum ScalableMatrixWithTieredPricingCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class ScalableMatrixWithTieredPricingCadenceConverter + : JsonConverter +{ + public override ScalableMatrixWithTieredPricingCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => ScalableMatrixWithTieredPricingCadence.OneTime, + "monthly" => ScalableMatrixWithTieredPricingCadence.Monthly, + "quarterly" => ScalableMatrixWithTieredPricingCadence.Quarterly, + "semi_annual" => ScalableMatrixWithTieredPricingCadence.SemiAnnual, + "annual" => ScalableMatrixWithTieredPricingCadence.Annual, + "custom" => ScalableMatrixWithTieredPricingCadence.Custom, + _ => (ScalableMatrixWithTieredPricingCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithTieredPricingCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithTieredPricingCadence.OneTime => "one_time", + ScalableMatrixWithTieredPricingCadence.Monthly => "monthly", + ScalableMatrixWithTieredPricingCadence.Quarterly => "quarterly", + ScalableMatrixWithTieredPricingCadence.SemiAnnual => "semi_annual", + ScalableMatrixWithTieredPricingCadence.Annual => "annual", + ScalableMatrixWithTieredPricingCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricingCompositePriceFilter, + ScalableMatrixWithTieredPricingCompositePriceFilterFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum< + string, + ScalableMatrixWithTieredPricingCompositePriceFilterOperator + > Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public ScalableMatrixWithTieredPricingCompositePriceFilter() { } + + public ScalableMatrixWithTieredPricingCompositePriceFilter( + ScalableMatrixWithTieredPricingCompositePriceFilter scalableMatrixWithTieredPricingCompositePriceFilter + ) + : base(scalableMatrixWithTieredPricingCompositePriceFilter) { } + + public ScalableMatrixWithTieredPricingCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingCompositePriceFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithTieredPricingCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricingCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ScalableMatrixWithTieredPricingCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(ScalableMatrixWithTieredPricingCompositePriceFilterFieldConverter))] +public enum ScalableMatrixWithTieredPricingCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class ScalableMatrixWithTieredPricingCompositePriceFilterFieldConverter + : JsonConverter +{ + public override ScalableMatrixWithTieredPricingCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID, + "item_id" => ScalableMatrixWithTieredPricingCompositePriceFilterField.ItemID, + "price_type" => ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceType, + "currency" => ScalableMatrixWithTieredPricingCompositePriceFilterField.Currency, + "pricing_unit_id" => + ScalableMatrixWithTieredPricingCompositePriceFilterField.PricingUnitID, + _ => (ScalableMatrixWithTieredPricingCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithTieredPricingCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceID => "price_id", + ScalableMatrixWithTieredPricingCompositePriceFilterField.ItemID => "item_id", + ScalableMatrixWithTieredPricingCompositePriceFilterField.PriceType => "price_type", + ScalableMatrixWithTieredPricingCompositePriceFilterField.Currency => "currency", + ScalableMatrixWithTieredPricingCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(ScalableMatrixWithTieredPricingCompositePriceFilterOperatorConverter))] +public enum ScalableMatrixWithTieredPricingCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class ScalableMatrixWithTieredPricingCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override ScalableMatrixWithTieredPricingCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes, + "excludes" => ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Excludes, + _ => (ScalableMatrixWithTieredPricingCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithTieredPricingCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Includes => "includes", + ScalableMatrixWithTieredPricingCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ScalableMatrixWithTieredPricingConversionRateConfigConverter))] +public record class ScalableMatrixWithTieredPricingConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ScalableMatrixWithTieredPricingConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ScalableMatrixWithTieredPricingConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ScalableMatrixWithTieredPricingConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ScalableMatrixWithTieredPricingConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ScalableMatrixWithTieredPricingConversionRateConfig" + ), + }; + } + + public static implicit operator ScalableMatrixWithTieredPricingConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ScalableMatrixWithTieredPricingConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ScalableMatrixWithTieredPricingConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ScalableMatrixWithTieredPricingConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ScalableMatrixWithTieredPricingConversionRateConfigConverter + : JsonConverter +{ + public override ScalableMatrixWithTieredPricingConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ScalableMatrixWithTieredPricingConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithTieredPricingConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(ScalableMatrixWithTieredPricingPriceTypeConverter))] +public enum ScalableMatrixWithTieredPricingPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class ScalableMatrixWithTieredPricingPriceTypeConverter + : JsonConverter +{ + public override ScalableMatrixWithTieredPricingPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => ScalableMatrixWithTieredPricingPriceType.UsagePrice, + "fixed_price" => ScalableMatrixWithTieredPricingPriceType.FixedPrice, + "composite_price" => ScalableMatrixWithTieredPricingPriceType.CompositePrice, + _ => (ScalableMatrixWithTieredPricingPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ScalableMatrixWithTieredPricingPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ScalableMatrixWithTieredPricingPriceType.UsagePrice => "usage_price", + ScalableMatrixWithTieredPricingPriceType.FixedPrice => "fixed_price", + ScalableMatrixWithTieredPricingPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_tiered_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig, + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + : JsonModel +{ + /// + /// Used for the scalable matrix first dimension + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); + } + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } + } + + /// + /// Tier pricing structure + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// Used for the scalable matrix second dimension (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.SecondDimension; + } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig() { } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig( + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig scalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig + ) + : base(scalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig) { } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor, + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactorFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor() + { } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor scalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + ) + : base( + scalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor + ) { } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigMatrixScalingFactor.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single tier entry with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier, + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTierFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier + : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier() { } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier( + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier scalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier + ) + : base(scalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier) { } + + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTierFromRaw + : IFromRawJson +{ + /// + public ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ScalableMatrixWithTieredPricingScalableMatrixWithTieredPricingConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class CumulativeGroupedBulk : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required CumulativeGroupedBulkConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + /// + /// Configuration for cumulative_grouped_bulk pricing + /// + public required CumulativeGroupedBulkCumulativeGroupedBulkConfig CumulativeGroupedBulkConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_bulk_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_bulk_config", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + this.CumulativeGroupedBulkConfig.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_bulk\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public CumulativeGroupedBulk() + { + this.ModelType = JsonSerializer.Deserialize("\"cumulative_grouped_bulk\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public CumulativeGroupedBulk(CumulativeGroupedBulk cumulativeGroupedBulk) + : base(cumulativeGroupedBulk) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public CumulativeGroupedBulk(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"cumulative_grouped_bulk\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + CumulativeGroupedBulk(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedBulk FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedBulkFromRaw : IFromRawJson +{ + /// + public CumulativeGroupedBulk FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedBulk.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CumulativeGroupedBulkBillingModeConverter))] +public enum CumulativeGroupedBulkBillingMode +{ + InAdvance, + InArrear, +} + +sealed class CumulativeGroupedBulkBillingModeConverter + : JsonConverter +{ + public override CumulativeGroupedBulkBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => CumulativeGroupedBulkBillingMode.InAdvance, + "in_arrear" => CumulativeGroupedBulkBillingMode.InArrear, + _ => (CumulativeGroupedBulkBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedBulkBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedBulkBillingMode.InAdvance => "in_advance", + CumulativeGroupedBulkBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CumulativeGroupedBulkCadenceConverter))] +public enum CumulativeGroupedBulkCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class CumulativeGroupedBulkCadenceConverter : JsonConverter +{ + public override CumulativeGroupedBulkCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => CumulativeGroupedBulkCadence.OneTime, + "monthly" => CumulativeGroupedBulkCadence.Monthly, + "quarterly" => CumulativeGroupedBulkCadence.Quarterly, + "semi_annual" => CumulativeGroupedBulkCadence.SemiAnnual, + "annual" => CumulativeGroupedBulkCadence.Annual, + "custom" => CumulativeGroupedBulkCadence.Custom, + _ => (CumulativeGroupedBulkCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedBulkCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedBulkCadence.OneTime => "one_time", + CumulativeGroupedBulkCadence.Monthly => "monthly", + CumulativeGroupedBulkCadence.Quarterly => "quarterly", + CumulativeGroupedBulkCadence.SemiAnnual => "semi_annual", + CumulativeGroupedBulkCadence.Annual => "annual", + CumulativeGroupedBulkCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + CumulativeGroupedBulkCompositePriceFilter, + CumulativeGroupedBulkCompositePriceFilterFromRaw + >) +)] +public sealed record class CumulativeGroupedBulkCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public CumulativeGroupedBulkCompositePriceFilter() { } + + public CumulativeGroupedBulkCompositePriceFilter( + CumulativeGroupedBulkCompositePriceFilter cumulativeGroupedBulkCompositePriceFilter + ) + : base(cumulativeGroupedBulkCompositePriceFilter) { } + + public CumulativeGroupedBulkCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedBulkCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedBulkCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedBulkCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public CumulativeGroupedBulkCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedBulkCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(CumulativeGroupedBulkCompositePriceFilterFieldConverter))] +public enum CumulativeGroupedBulkCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class CumulativeGroupedBulkCompositePriceFilterFieldConverter + : JsonConverter +{ + public override CumulativeGroupedBulkCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => CumulativeGroupedBulkCompositePriceFilterField.PriceID, + "item_id" => CumulativeGroupedBulkCompositePriceFilterField.ItemID, + "price_type" => CumulativeGroupedBulkCompositePriceFilterField.PriceType, + "currency" => CumulativeGroupedBulkCompositePriceFilterField.Currency, + "pricing_unit_id" => CumulativeGroupedBulkCompositePriceFilterField.PricingUnitID, + _ => (CumulativeGroupedBulkCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedBulkCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedBulkCompositePriceFilterField.PriceID => "price_id", + CumulativeGroupedBulkCompositePriceFilterField.ItemID => "item_id", + CumulativeGroupedBulkCompositePriceFilterField.PriceType => "price_type", + CumulativeGroupedBulkCompositePriceFilterField.Currency => "currency", + CumulativeGroupedBulkCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(CumulativeGroupedBulkCompositePriceFilterOperatorConverter))] +public enum CumulativeGroupedBulkCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class CumulativeGroupedBulkCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override CumulativeGroupedBulkCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => CumulativeGroupedBulkCompositePriceFilterOperator.Includes, + "excludes" => CumulativeGroupedBulkCompositePriceFilterOperator.Excludes, + _ => (CumulativeGroupedBulkCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedBulkCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedBulkCompositePriceFilterOperator.Includes => "includes", + CumulativeGroupedBulkCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CumulativeGroupedBulkConversionRateConfigConverter))] +public record class CumulativeGroupedBulkConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedBulkConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedBulkConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedBulkConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedBulkConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedBulkConversionRateConfig" + ), + }; + } + + public static implicit operator CumulativeGroupedBulkConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator CumulativeGroupedBulkConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedBulkConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(CumulativeGroupedBulkConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedBulkConversionRateConfigConverter + : JsonConverter +{ + public override CumulativeGroupedBulkConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new CumulativeGroupedBulkConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedBulkConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for cumulative_grouped_bulk pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + CumulativeGroupedBulkCumulativeGroupedBulkConfig, + CumulativeGroupedBulkCumulativeGroupedBulkConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedBulkCumulativeGroupedBulkConfig : JsonModel +{ + /// + /// Each tier lower bound must have the same group of values. + /// + public required IReadOnlyList DimensionValues + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "dimension_values"); + } + init { JsonModel.Set(this._rawData, "dimension_values", value); } + } + + /// + /// Grouping key name + /// + public required string Group + { + get { return JsonModel.GetNotNullClass(this.RawData, "group"); } + init { JsonModel.Set(this._rawData, "group", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.DimensionValues) + { + item.Validate(); + } + _ = this.Group; + } + + public CumulativeGroupedBulkCumulativeGroupedBulkConfig() { } + + public CumulativeGroupedBulkCumulativeGroupedBulkConfig( + CumulativeGroupedBulkCumulativeGroupedBulkConfig cumulativeGroupedBulkCumulativeGroupedBulkConfig + ) + : base(cumulativeGroupedBulkCumulativeGroupedBulkConfig) { } + + public CumulativeGroupedBulkCumulativeGroupedBulkConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedBulkCumulativeGroupedBulkConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedBulkCumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedBulkCumulativeGroupedBulkConfigFromRaw + : IFromRawJson +{ + /// + public CumulativeGroupedBulkCumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedBulkCumulativeGroupedBulkConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a dimension value entry +/// +[JsonConverter( + typeof(JsonModelConverter< + CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue, + CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValueFromRaw + >) +)] +public sealed record class CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue + : JsonModel +{ + /// + /// Grouping key value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Unit amount for this combination + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue() { } + + public CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue( + CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue cumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue + ) + : base(cumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue) { } + + public CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValueFromRaw + : IFromRawJson +{ + /// + public CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedBulkCumulativeGroupedBulkConfigDimensionValue.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CumulativeGroupedBulkPriceTypeConverter))] +public enum CumulativeGroupedBulkPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class CumulativeGroupedBulkPriceTypeConverter : JsonConverter +{ + public override CumulativeGroupedBulkPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => CumulativeGroupedBulkPriceType.UsagePrice, + "fixed_price" => CumulativeGroupedBulkPriceType.FixedPrice, + "composite_price" => CumulativeGroupedBulkPriceType.CompositePrice, + _ => (CumulativeGroupedBulkPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedBulkPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedBulkPriceType.UsagePrice => "usage_price", + CumulativeGroupedBulkPriceType.FixedPrice => "fixed_price", + CumulativeGroupedBulkPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class CumulativeGroupedAllocation : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "billing_mode"); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "composite_price_filters"); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required CumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required CumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public CumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public CumulativeGroupedAllocation(CumulativeGroupedAllocation cumulativeGroupedAllocation) + : base(cumulativeGroupedAllocation) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public CumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + CumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationFromRaw : IFromRawJson +{ + /// + public CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CumulativeGroupedAllocationBillingModeConverter))] +public enum CumulativeGroupedAllocationBillingMode +{ + InAdvance, + InArrear, +} + +sealed class CumulativeGroupedAllocationBillingModeConverter + : JsonConverter +{ + public override CumulativeGroupedAllocationBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => CumulativeGroupedAllocationBillingMode.InAdvance, + "in_arrear" => CumulativeGroupedAllocationBillingMode.InArrear, + _ => (CumulativeGroupedAllocationBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedAllocationBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedAllocationBillingMode.InAdvance => "in_advance", + CumulativeGroupedAllocationBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CumulativeGroupedAllocationCadenceConverter))] +public enum CumulativeGroupedAllocationCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class CumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override CumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => CumulativeGroupedAllocationCadence.OneTime, + "monthly" => CumulativeGroupedAllocationCadence.Monthly, + "quarterly" => CumulativeGroupedAllocationCadence.Quarterly, + "semi_annual" => CumulativeGroupedAllocationCadence.SemiAnnual, + "annual" => CumulativeGroupedAllocationCadence.Annual, + "custom" => CumulativeGroupedAllocationCadence.Custom, + _ => (CumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedAllocationCadence.OneTime => "one_time", + CumulativeGroupedAllocationCadence.Monthly => "monthly", + CumulativeGroupedAllocationCadence.Quarterly => "quarterly", + CumulativeGroupedAllocationCadence.SemiAnnual => "semi_annual", + CumulativeGroupedAllocationCadence.Annual => "annual", + CumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + CumulativeGroupedAllocationCompositePriceFilter, + CumulativeGroupedAllocationCompositePriceFilterFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum< + string, + CumulativeGroupedAllocationCompositePriceFilterOperator + > Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public CumulativeGroupedAllocationCompositePriceFilter() { } + + public CumulativeGroupedAllocationCompositePriceFilter( + CumulativeGroupedAllocationCompositePriceFilter cumulativeGroupedAllocationCompositePriceFilter + ) + : base(cumulativeGroupedAllocationCompositePriceFilter) { } + + public CumulativeGroupedAllocationCompositePriceFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationCompositePriceFilterFromRaw + : IFromRawJson +{ + /// + public CumulativeGroupedAllocationCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedAllocationCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(CumulativeGroupedAllocationCompositePriceFilterFieldConverter))] +public enum CumulativeGroupedAllocationCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class CumulativeGroupedAllocationCompositePriceFilterFieldConverter + : JsonConverter +{ + public override CumulativeGroupedAllocationCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => CumulativeGroupedAllocationCompositePriceFilterField.PriceID, + "item_id" => CumulativeGroupedAllocationCompositePriceFilterField.ItemID, + "price_type" => CumulativeGroupedAllocationCompositePriceFilterField.PriceType, + "currency" => CumulativeGroupedAllocationCompositePriceFilterField.Currency, + "pricing_unit_id" => CumulativeGroupedAllocationCompositePriceFilterField.PricingUnitID, + _ => (CumulativeGroupedAllocationCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedAllocationCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedAllocationCompositePriceFilterField.PriceID => "price_id", + CumulativeGroupedAllocationCompositePriceFilterField.ItemID => "item_id", + CumulativeGroupedAllocationCompositePriceFilterField.PriceType => "price_type", + CumulativeGroupedAllocationCompositePriceFilterField.Currency => "currency", + CumulativeGroupedAllocationCompositePriceFilterField.PricingUnitID => + "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(CumulativeGroupedAllocationCompositePriceFilterOperatorConverter))] +public enum CumulativeGroupedAllocationCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class CumulativeGroupedAllocationCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override CumulativeGroupedAllocationCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => CumulativeGroupedAllocationCompositePriceFilterOperator.Includes, + "excludes" => CumulativeGroupedAllocationCompositePriceFilterOperator.Excludes, + _ => (CumulativeGroupedAllocationCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedAllocationCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedAllocationCompositePriceFilterOperator.Includes => "includes", + CumulativeGroupedAllocationCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(CumulativeGroupedAllocationConversionRateConfigConverter))] +public record class CumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(CumulativeGroupedAllocationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override CumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new CumulativeGroupedAllocationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + CumulativeGroupedAllocationConfig, + CumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationConfig : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public CumulativeGroupedAllocationConfig() { } + + public CumulativeGroupedAllocationConfig( + CumulativeGroupedAllocationConfig cumulativeGroupedAllocationConfig + ) + : base(cumulativeGroupedAllocationConfig) { } + + public CumulativeGroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationConfigFromRaw : IFromRawJson +{ + /// + public CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => CumulativeGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(CumulativeGroupedAllocationPriceTypeConverter))] +public enum CumulativeGroupedAllocationPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class CumulativeGroupedAllocationPriceTypeConverter + : JsonConverter +{ + public override CumulativeGroupedAllocationPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => CumulativeGroupedAllocationPriceType.UsagePrice, + "fixed_price" => CumulativeGroupedAllocationPriceType.FixedPrice, + "composite_price" => CumulativeGroupedAllocationPriceType.CompositePrice, + _ => (CumulativeGroupedAllocationPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CumulativeGroupedAllocationPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CumulativeGroupedAllocationPriceType.UsagePrice => "usage_price", + CumulativeGroupedAllocationPriceType.FixedPrice => "fixed_price", + CumulativeGroupedAllocationPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceMinimum : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required PriceMinimumConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Configuration for minimum pricing + /// + public required PriceMinimumMinimumConfig MinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "minimum_config", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + this.MinimumConfig.Validate(); + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"minimum\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public PriceMinimum() + { + this.ModelType = JsonSerializer.Deserialize("\"minimum\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public PriceMinimum(PriceMinimum priceMinimum) + : base(priceMinimum) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public PriceMinimum(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"minimum\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + PriceMinimum(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceMinimum FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceMinimumFromRaw : IFromRawJson +{ + /// + public PriceMinimum FromRawUnchecked(IReadOnlyDictionary rawData) => + PriceMinimum.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceMinimumBillingModeConverter))] +public enum PriceMinimumBillingMode +{ + InAdvance, + InArrear, +} + +sealed class PriceMinimumBillingModeConverter : JsonConverter +{ + public override PriceMinimumBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => PriceMinimumBillingMode.InAdvance, + "in_arrear" => PriceMinimumBillingMode.InArrear, + _ => (PriceMinimumBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceMinimumBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceMinimumBillingMode.InAdvance => "in_advance", + PriceMinimumBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PriceMinimumCadenceConverter))] +public enum PriceMinimumCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class PriceMinimumCadenceConverter : JsonConverter +{ + public override PriceMinimumCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => PriceMinimumCadence.OneTime, + "monthly" => PriceMinimumCadence.Monthly, + "quarterly" => PriceMinimumCadence.Quarterly, + "semi_annual" => PriceMinimumCadence.SemiAnnual, + "annual" => PriceMinimumCadence.Annual, + "custom" => PriceMinimumCadence.Custom, + _ => (PriceMinimumCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceMinimumCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceMinimumCadence.OneTime => "one_time", + PriceMinimumCadence.Monthly => "monthly", + PriceMinimumCadence.Quarterly => "quarterly", + PriceMinimumCadence.SemiAnnual => "semi_annual", + PriceMinimumCadence.Annual => "annual", + PriceMinimumCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceMinimumCompositePriceFilter, + PriceMinimumCompositePriceFilterFromRaw + >) +)] +public sealed record class PriceMinimumCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "field"); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PriceMinimumCompositePriceFilter() { } + + public PriceMinimumCompositePriceFilter( + PriceMinimumCompositePriceFilter priceMinimumCompositePriceFilter + ) + : base(priceMinimumCompositePriceFilter) { } + + public PriceMinimumCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceMinimumCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceMinimumCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public PriceMinimumCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceMinimumCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PriceMinimumCompositePriceFilterFieldConverter))] +public enum PriceMinimumCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PriceMinimumCompositePriceFilterFieldConverter + : JsonConverter +{ + public override PriceMinimumCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PriceMinimumCompositePriceFilterField.PriceID, + "item_id" => PriceMinimumCompositePriceFilterField.ItemID, + "price_type" => PriceMinimumCompositePriceFilterField.PriceType, + "currency" => PriceMinimumCompositePriceFilterField.Currency, + "pricing_unit_id" => PriceMinimumCompositePriceFilterField.PricingUnitID, + _ => (PriceMinimumCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceMinimumCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceMinimumCompositePriceFilterField.PriceID => "price_id", + PriceMinimumCompositePriceFilterField.ItemID => "item_id", + PriceMinimumCompositePriceFilterField.PriceType => "price_type", + PriceMinimumCompositePriceFilterField.Currency => "currency", + PriceMinimumCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PriceMinimumCompositePriceFilterOperatorConverter))] +public enum PriceMinimumCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class PriceMinimumCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override PriceMinimumCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PriceMinimumCompositePriceFilterOperator.Includes, + "excludes" => PriceMinimumCompositePriceFilterOperator.Excludes, + _ => (PriceMinimumCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceMinimumCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceMinimumCompositePriceFilterOperator.Includes => "includes", + PriceMinimumCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PriceMinimumConversionRateConfigConverter))] +public record class PriceMinimumConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceMinimumConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceMinimumConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceMinimumConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceMinimumConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceMinimumConversionRateConfig" + ), + }; + } + + public static implicit operator PriceMinimumConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceMinimumConversionRateConfig( + SharedTieredConversionRateConfig value ) => new(value); - public static PriceVariants::TieredPackage Create(PriceProperties::TieredPackage value) => - new(value); + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceMinimumConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceMinimumConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceMinimumConversionRateConfigConverter + : JsonConverter +{ + public override PriceMinimumConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceMinimumConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceMinimumConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PriceMinimumMinimumConfig : JsonModel +{ + /// + /// The minimum amount to apply + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// If true, subtotals from this price are prorated based on the service period + /// + public bool? Prorated + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorated"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorated", value); + } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.Prorated; + } + + public PriceMinimumMinimumConfig() { } + + public PriceMinimumMinimumConfig(PriceMinimumMinimumConfig priceMinimumMinimumConfig) + : base(priceMinimumMinimumConfig) { } + + public PriceMinimumMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceMinimumMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceMinimumMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceMinimumMinimumConfig(string minimumAmount) + : this() + { + this.MinimumAmount = minimumAmount; + } +} + +class PriceMinimumMinimumConfigFromRaw : IFromRawJson +{ + /// + public PriceMinimumMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceMinimumMinimumConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceMinimumPriceTypeConverter))] +public enum PriceMinimumPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class PriceMinimumPriceTypeConverter : JsonConverter +{ + public override PriceMinimumPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => PriceMinimumPriceType.UsagePrice, + "fixed_price" => PriceMinimumPriceType.FixedPrice, + "composite_price" => PriceMinimumPriceType.CompositePrice, + _ => (PriceMinimumPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceMinimumPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceMinimumPriceType.UsagePrice => "usage_price", + PriceMinimumPriceType.FixedPrice => "fixed_price", + PriceMinimumPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Percent : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } - public static PriceVariants::GroupedTiered Create(PriceProperties::GroupedTiered value) => - new(value); + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } - public static PriceVariants::TieredWithMinimum Create( - PriceProperties::TieredWithMinimum value - ) => new(value); + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } - public static PriceVariants::TieredPackageWithMinimum Create( - PriceProperties::TieredPackageWithMinimum value - ) => new(value); + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } - public static PriceVariants::PackageWithAllocation Create( - PriceProperties::PackageWithAllocation value - ) => new(value); + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } - public static PriceVariants::UnitWithPercent Create(PriceProperties::UnitWithPercent value) => - new(value); + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } - public static PriceVariants::MatrixWithAllocation Create( - PriceProperties::MatrixWithAllocation value - ) => new(value); + public required PercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } - public static PriceVariants::TieredWithProration Create( - PriceProperties::TieredWithProration value - ) => new(value); + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } - public static PriceVariants::UnitWithProration Create( - PriceProperties::UnitWithProration value - ) => new(value); + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } - public static PriceVariants::GroupedAllocation Create( - PriceProperties::GroupedAllocation value - ) => new(value); + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } - public static PriceVariants::GroupedWithProratedMinimum Create( - PriceProperties::GroupedWithProratedMinimum value - ) => new(value); + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } - public static PriceVariants::GroupedWithMeteredMinimum Create( - PriceProperties::GroupedWithMeteredMinimum value - ) => new(value); + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } - public static PriceVariants::MatrixWithDisplayName Create( - PriceProperties::MatrixWithDisplayName value - ) => new(value); + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } - public static PriceVariants::BulkWithProration Create( - PriceProperties::BulkWithProration value - ) => new(value); + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } - public static PriceVariants::GroupedTieredPackage Create( - PriceProperties::GroupedTieredPackage value - ) => new(value); + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required PercentConfig PercentConfig + { + get { return JsonModel.GetNotNullClass(this.RawData, "percent_config"); } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Percent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Percent(Percent percent) + : base(percent) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public Percent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + Percent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Percent FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentFromRaw : IFromRawJson +{ + /// + public Percent FromRawUnchecked(IReadOnlyDictionary rawData) => + Percent.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PercentBillingModeConverter))] +public enum PercentBillingMode +{ + InAdvance, + InArrear, +} + +sealed class PercentBillingModeConverter : JsonConverter +{ + public override PercentBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => PercentBillingMode.InAdvance, + "in_arrear" => PercentBillingMode.InArrear, + _ => (PercentBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentBillingMode.InAdvance => "in_advance", + PercentBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PercentCadenceConverter))] +public enum PercentCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class PercentCadenceConverter : JsonConverter +{ + public override PercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => PercentCadence.OneTime, + "monthly" => PercentCadence.Monthly, + "quarterly" => PercentCadence.Quarterly, + "semi_annual" => PercentCadence.SemiAnnual, + "annual" => PercentCadence.Annual, + "custom" => PercentCadence.Custom, + _ => (PercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentCadence.OneTime => "one_time", + PercentCadence.Monthly => "monthly", + PercentCadence.Quarterly => "quarterly", + PercentCadence.SemiAnnual => "semi_annual", + PercentCadence.Annual => "annual", + PercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PercentCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public PercentCompositePriceFilter() { } + + public PercentCompositePriceFilter(PercentCompositePriceFilter percentCompositePriceFilter) + : base(percentCompositePriceFilter) { } + + public PercentCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PercentCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public PercentCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PercentCompositePriceFilter.FromRawUnchecked(rawData); +} - public static PriceVariants::MaxGroupTieredPackage Create( - PriceProperties::MaxGroupTieredPackage value +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(PercentCompositePriceFilterFieldConverter))] +public enum PercentCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class PercentCompositePriceFilterFieldConverter + : JsonConverter +{ + public override PercentCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => PercentCompositePriceFilterField.PriceID, + "item_id" => PercentCompositePriceFilterField.ItemID, + "price_type" => PercentCompositePriceFilterField.PriceType, + "currency" => PercentCompositePriceFilterField.Currency, + "pricing_unit_id" => PercentCompositePriceFilterField.PricingUnitID, + _ => (PercentCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentCompositePriceFilterField.PriceID => "price_id", + PercentCompositePriceFilterField.ItemID => "item_id", + PercentCompositePriceFilterField.PriceType => "price_type", + PercentCompositePriceFilterField.Currency => "currency", + PercentCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(PercentCompositePriceFilterOperatorConverter))] +public enum PercentCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class PercentCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override PercentCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => PercentCompositePriceFilterOperator.Includes, + "excludes" => PercentCompositePriceFilterOperator.Excludes, + _ => (PercentCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentCompositePriceFilterOperator.Includes => "includes", + PercentCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PercentConversionRateConfigConverter))] +public record class PercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ), + }; + } + + public static implicit operator PercentConversionRateConfig( + SharedUnitConversionRateConfig value ) => new(value); - public static PriceVariants::ScalableMatrixWithUnitPricing Create( - PriceProperties::ScalableMatrixWithUnitPricing value + public static implicit operator PercentConversionRateConfig( + SharedTieredConversionRateConfig value ) => new(value); - public static PriceVariants::ScalableMatrixWithTieredPricing Create( - PriceProperties::ScalableMatrixWithTieredPricing value + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PercentConversionRateConfigConverter : JsonConverter +{ + public override PercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PercentConfig() { } + + public PercentConfig(PercentConfig percentConfig) + : base(percentConfig) { } + + public PercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PercentConfig FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PercentConfigFromRaw : IFromRawJson +{ + /// + public PercentConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + PercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PercentPriceTypeConverter))] +public enum PercentPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class PercentPriceTypeConverter : JsonConverter +{ + public override PercentPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => PercentPriceType.UsagePrice, + "fixed_price" => PercentPriceType.FixedPrice, + "composite_price" => PercentPriceType.CompositePrice, + _ => (PercentPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PercentPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PercentPriceType.UsagePrice => "usage_price", + PercentPriceType.FixedPrice => "fixed_price", + PercentPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventOutput : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required BillableMetricTiny? BillableMetric + { + get + { + return JsonModel.GetNullableClass(this.RawData, "billable_metric"); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required BillingCycleConfiguration BillingCycleConfiguration + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + public required ApiEnum BillingMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "billing_mode" + ); + } + init { JsonModel.Set(this._rawData, "billing_mode", value); } + } + + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + public required IReadOnlyList? CompositePriceFilters + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "composite_price_filters" + ); + } + init { JsonModel.Set(this._rawData, "composite_price_filters", value); } + } + + public required double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + public required EventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required Allocation? CreditAllocation + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_allocation"); } + init { JsonModel.Set(this._rawData, "credit_allocation", value); } + } + + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + [System::Obsolete("deprecated")] + public required SharedDiscount? Discount + { + get { return JsonModel.GetNullableClass(this.RawData, "discount"); } + init { JsonModel.Set(this._rawData, "discount", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required EventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + public required string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + public required double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + public required BillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// A minimal representation of an Item containing only the essential identifying information. + /// + public required ItemSlim Item + { + get { return JsonModel.GetNotNullClass(this.RawData, "item"); } + init { JsonModel.Set(this._rawData, "item", value); } + } + + [System::Obsolete("deprecated")] + public required Maximum? Maximum + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum"); } + init { JsonModel.Set(this._rawData, "maximum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// User specified key-value pairs for the resource. If not present, this defaults + /// to an empty dictionary. Individual keys can be removed by setting the value + /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` + /// to `null`. + /// + public required IReadOnlyDictionary Metadata + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + [System::Obsolete("deprecated")] + public required Minimum? Minimum + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + [System::Obsolete("deprecated")] + public required string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + public required long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + public required ApiEnum PriceType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_type" + ); + } + init { JsonModel.Set(this._rawData, "price_type", value); } + } + + /// + /// The price id this price replaces. This price will take the place of the replaced + /// price in plan version migrations. + /// + public required string? ReplacesPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + public DimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + this.BillableMetric?.Validate(); + this.BillingCycleConfiguration.Validate(); + this.BillingMode.Validate(); + this.Cadence.Validate(); + foreach (var item in this.CompositePriceFilters ?? []) + { + item.Validate(); + } + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.CreatedAt; + this.CreditAllocation?.Validate(); + _ = this.Currency; + this.Discount?.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + this.InvoicingCycleConfiguration?.Validate(); + this.Item.Validate(); + this.Maximum?.Validate(); + _ = this.MaximumAmount; + _ = this.Metadata; + this.Minimum?.Validate(); + _ = this.MinimumAmount; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.PlanPhaseOrder; + this.PriceType.Validate(); + _ = this.ReplacesPriceID; + this.DimensionalPriceConfiguration?.Validate(); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public EventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public EventOutput(EventOutput eventOutput) + : base(eventOutput) { } + + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + public EventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [System::Obsolete( + "Required properties are deprecated: discount, maximum, maximum_amount, minimum, minimum_amount" + )] + [SetsRequiredMembers] + EventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static EventOutput FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputFromRaw : IFromRawJson +{ + /// + public EventOutput FromRawUnchecked(IReadOnlyDictionary rawData) => + EventOutput.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(EventOutputBillingModeConverter))] +public enum EventOutputBillingMode +{ + InAdvance, + InArrear, +} + +sealed class EventOutputBillingModeConverter : JsonConverter +{ + public override EventOutputBillingMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "in_advance" => EventOutputBillingMode.InAdvance, + "in_arrear" => EventOutputBillingMode.InArrear, + _ => (EventOutputBillingMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EventOutputBillingMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EventOutputBillingMode.InAdvance => "in_advance", + EventOutputBillingMode.InArrear => "in_arrear", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(EventOutputCadenceConverter))] +public enum EventOutputCadence +{ + OneTime, + Monthly, + Quarterly, + SemiAnnual, + Annual, + Custom, +} + +sealed class EventOutputCadenceConverter : JsonConverter +{ + public override EventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "one_time" => EventOutputCadence.OneTime, + "monthly" => EventOutputCadence.Monthly, + "quarterly" => EventOutputCadence.Quarterly, + "semi_annual" => EventOutputCadence.SemiAnnual, + "annual" => EventOutputCadence.Annual, + "custom" => EventOutputCadence.Custom, + _ => (EventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EventOutputCadence.OneTime => "one_time", + EventOutputCadence.Monthly => "monthly", + EventOutputCadence.Quarterly => "quarterly", + EventOutputCadence.SemiAnnual => "semi_annual", + EventOutputCadence.Annual => "annual", + EventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + EventOutputCompositePriceFilter, + EventOutputCompositePriceFilterFromRaw + >) +)] +public sealed record class EventOutputCompositePriceFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "operator"); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public EventOutputCompositePriceFilter() { } + + public EventOutputCompositePriceFilter( + EventOutputCompositePriceFilter eventOutputCompositePriceFilter + ) + : base(eventOutputCompositePriceFilter) { } + + public EventOutputCompositePriceFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputCompositePriceFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static EventOutputCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputCompositePriceFilterFromRaw : IFromRawJson +{ + /// + public EventOutputCompositePriceFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => EventOutputCompositePriceFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(EventOutputCompositePriceFilterFieldConverter))] +public enum EventOutputCompositePriceFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class EventOutputCompositePriceFilterFieldConverter + : JsonConverter +{ + public override EventOutputCompositePriceFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => EventOutputCompositePriceFilterField.PriceID, + "item_id" => EventOutputCompositePriceFilterField.ItemID, + "price_type" => EventOutputCompositePriceFilterField.PriceType, + "currency" => EventOutputCompositePriceFilterField.Currency, + "pricing_unit_id" => EventOutputCompositePriceFilterField.PricingUnitID, + _ => (EventOutputCompositePriceFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EventOutputCompositePriceFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EventOutputCompositePriceFilterField.PriceID => "price_id", + EventOutputCompositePriceFilterField.ItemID => "item_id", + EventOutputCompositePriceFilterField.PriceType => "price_type", + EventOutputCompositePriceFilterField.Currency => "currency", + EventOutputCompositePriceFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(EventOutputCompositePriceFilterOperatorConverter))] +public enum EventOutputCompositePriceFilterOperator +{ + Includes, + Excludes, +} + +sealed class EventOutputCompositePriceFilterOperatorConverter + : JsonConverter +{ + public override EventOutputCompositePriceFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => EventOutputCompositePriceFilterOperator.Includes, + "excludes" => EventOutputCompositePriceFilterOperator.Excludes, + _ => (EventOutputCompositePriceFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EventOutputCompositePriceFilterOperator value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EventOutputCompositePriceFilterOperator.Includes => "includes", + EventOutputCompositePriceFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(EventOutputConversionRateConfigConverter))] +public record class EventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value ) => new(value); - public static PriceVariants::CumulativeGroupedBulk Create( - PriceProperties::CumulativeGroupedBulk value + public static implicit operator EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value ) => new(value); - public abstract void Validate(); + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(EventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EventOutputConversionRateConfigConverter + : JsonConverter +{ + public override EventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new EventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + EventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public EventOutputConfig() { } + + public EventOutputConfig(EventOutputConfig eventOutputConfig) + : base(eventOutputConfig) { } + + public EventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class EventOutputConfigFromRaw : IFromRawJson +{ + /// + public EventOutputConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + EventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(EventOutputPriceTypeConverter))] +public enum EventOutputPriceType +{ + UsagePrice, + FixedPrice, + CompositePrice, +} + +sealed class EventOutputPriceTypeConverter : JsonConverter +{ + public override EventOutputPriceType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage_price" => EventOutputPriceType.UsagePrice, + "fixed_price" => EventOutputPriceType.FixedPrice, + "composite_price" => EventOutputPriceType.CompositePrice, + _ => (EventOutputPriceType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + EventOutputPriceType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + EventOutputPriceType.UsagePrice => "usage_price", + EventOutputPriceType.FixedPrice => "fixed_price", + EventOutputPriceType.CompositePrice => "composite_price", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } } diff --git a/src/Orb/Models/PriceInterval.cs b/src/Orb/Models/PriceInterval.cs index 8c630ab4..3b24e94c 100644 --- a/src/Orb/Models/PriceInterval.cs +++ b/src/Orb/Models/PriceInterval.cs @@ -1,9 +1,10 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; @@ -11,20 +12,13 @@ namespace Orb.Models; /// The Price Interval resource represents a period of time for which a price will /// bill on a subscription. A subscription’s price intervals define its billing behavior. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceInterval : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceInterval : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -32,20 +26,19 @@ public required string ID /// public required long BillingCycleDay { - get - { - if (!this.Properties.TryGetValue("billing_cycle_day", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_day", - "Missing required argument" - ); + get { return JsonModel.GetNotNullStruct(this.RawData, "billing_cycle_day"); } + init { JsonModel.Set(this._rawData, "billing_cycle_day", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_day"] = Json::JsonSerializer.SerializeToElement(value); - } + /// + /// For in-arrears prices. If true, and the price interval ends mid-cycle, the + /// final line item will be deferred to the next scheduled invoice instead of + /// being billed mid-cycle. + /// + public required bool CanDeferBilling + { + get { return JsonModel.GetNotNullStruct(this.RawData, "can_defer_billing"); } + init { JsonModel.Set(this._rawData, "can_defer_billing", value); } } /// @@ -53,28 +46,16 @@ public required long BillingCycleDay /// that the instant returned is exactly the end of the billing period. Set to /// null if this price interval is not currently active. /// - public required System::DateTime? CurrentBillingPeriodEndDate + public required DateTimeOffset? CurrentBillingPeriodEndDate { get { - if ( - !this.Properties.TryGetValue( - "current_billing_period_end_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "current_billing_period_end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["current_billing_period_end_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "current_billing_period_end_date" + ); } + init { JsonModel.Set(this._rawData, "current_billing_period_end_date", value); } } /// @@ -82,47 +63,26 @@ public required long BillingCycleDay /// the instant returned is exactly the beginning of the billing period. Set to /// null if this price interval is not currently active. /// - public required System::DateTime? CurrentBillingPeriodStartDate + public required DateTimeOffset? CurrentBillingPeriodStartDate { get { - if ( - !this.Properties.TryGetValue( - "current_billing_period_start_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "current_billing_period_start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["current_billing_period_start_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "current_billing_period_start_date" + ); } + init { JsonModel.Set(this._rawData, "current_billing_period_start_date", value); } } /// /// The end date of the price interval. This is the date that Orb stops billing /// for this price. /// - public required System::DateTime? EndDate + public required DateTimeOffset? EndDate { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// @@ -130,118 +90,69 @@ public required long BillingCycleDay /// public required string? Filter { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filter", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } } /// - /// The fixed fee quantity transitions for this price interval. This is only relevant - /// for fixed fees. + /// The fixed fee quantity transitions for this price interval. This is only + /// relevant for fixed fees. /// - public required Generic::List? FixedFeeQuantityTransitions + public required IReadOnlyList? FixedFeeQuantityTransitions { get { - if ( - !this.Properties.TryGetValue( - "fixed_fee_quantity_transitions", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "fixed_fee_quantity_transitions", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawData, + "fixed_fee_quantity_transitions" ); } - set - { - this.Properties["fixed_fee_quantity_transitions"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "fixed_fee_quantity_transitions", value); } } /// /// The Price resource represents a price that can be billed on a subscription, - /// resulting in a charge on an invoice in the form of an invoice line item. Prices - /// take a quantity and determine an amount to bill. + /// resulting in a charge on an invoice in the form of an invoice line item. + /// Prices take a quantity and determine an amount to bill. /// - /// Orb supports a few different pricing models out of the box. Each of these models - /// is serialized differently in a given Price object. The model_type field determines - /// the key for the configuration object that is present. + /// Orb supports a few different pricing models out of the box. Each of + /// these models is serialized differently in a given Price object. The model_type + /// field determines the key for the configuration object that is present. /// - /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) + /// For more on the types of prices, see [the core concepts documentation](/core-concepts#plan-and-price) /// public required Price Price { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("price", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price"); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } } /// /// The start date of the price interval. This is the date that Orb starts billing /// for this price. /// - public required System::DateTime StartDate + public required DateTimeOffset StartDate { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } } /// /// A list of customer IDs whose usage events will be aggregated and billed under /// this price interval. /// - public required Generic::List? UsageCustomerIDs + public required IReadOnlyList? UsageCustomerIDs { - get - { - if (!this.Properties.TryGetValue("usage_customer_ids", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_customer_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } } + /// public override void Validate() { _ = this.ID; _ = this.BillingCycleDay; + _ = this.CanDeferBilling; _ = this.CurrentBillingPeriodEndDate; _ = this.CurrentBillingPeriodStartDate; _ = this.EndDate; @@ -252,26 +163,37 @@ public override void Validate() } this.Price.Validate(); _ = this.StartDate; - foreach (var item in this.UsageCustomerIDs ?? []) - { - _ = item; - } + _ = this.UsageCustomerIDs; } public PriceInterval() { } + public PriceInterval(PriceInterval priceInterval) + : base(priceInterval) { } + + public PriceInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + PriceInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static PriceInterval FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static PriceInterval FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class PriceIntervalFromRaw : IFromRawJson +{ + /// + public PriceInterval FromRawUnchecked(IReadOnlyDictionary rawData) => + PriceInterval.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/PriceProperties/BPS.cs b/src/Orb/Models/PriceProperties/BPS.cs deleted file mode 100644 index 9e37cf6a..00000000 --- a/src/Orb/Models/PriceProperties/BPS.cs +++ /dev/null @@ -1,516 +0,0 @@ -using BPSProperties = Orb.Models.PriceProperties.BPSProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BPS : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::BPSConfig BPSConfig - { - get - { - if (!this.Properties.TryGetValue("bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bps_config"); - } - set { this.Properties["bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BPSProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BPSProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BPSProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required BPSProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.BPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public BPS() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BPS(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BPS FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/BPSProperties/Cadence.cs b/src/Orb/Models/PriceProperties/BPSProperties/Cadence.cs deleted file mode 100644 index d320f5b8..00000000 --- a/src/Orb/Models/PriceProperties/BPSProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BPSProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/BPSProperties/ConversionRateConfig.cs deleted file mode 100644 index 5593bf57..00000000 --- a/src/Orb/Models/PriceProperties/BPSProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.BPSProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BPSProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/BPSProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/BPSProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 7542fea6..00000000 --- a/src/Orb/Models/PriceProperties/BPSProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using BPSProperties = Orb.Models.PriceProperties.BPSProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BPSProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : BPSProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : BPSProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/BPSProperties/ModelType.cs b/src/Orb/Models/PriceProperties/BPSProperties/ModelType.cs deleted file mode 100644 index 4b294553..00000000 --- a/src/Orb/Models/PriceProperties/BPSProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BPS = new("bps"); - - readonly string _value = value; - - public enum Value - { - BPS, - } - - public Value Known() => - _value switch - { - "bps" => Value.BPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BPSProperties/PriceType.cs b/src/Orb/Models/PriceProperties/BPSProperties/PriceType.cs deleted file mode 100644 index 8fba1b26..00000000 --- a/src/Orb/Models/PriceProperties/BPSProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/Bulk.cs b/src/Orb/Models/PriceProperties/Bulk.cs deleted file mode 100644 index c724cec2..00000000 --- a/src/Orb/Models/PriceProperties/Bulk.cs +++ /dev/null @@ -1,516 +0,0 @@ -using BulkProperties = Orb.Models.PriceProperties.BulkProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Bulk : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::BulkConfig BulkConfig - { - get - { - if (!this.Properties.TryGetValue("bulk_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_config"); - } - set { this.Properties["bulk_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required BulkProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.BulkConfig.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public Bulk() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Bulk(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Bulk FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkBPS.cs b/src/Orb/Models/PriceProperties/BulkBPS.cs deleted file mode 100644 index b9ff5f5d..00000000 --- a/src/Orb/Models/PriceProperties/BulkBPS.cs +++ /dev/null @@ -1,520 +0,0 @@ -using BulkBPSProperties = Orb.Models.PriceProperties.BulkBPSProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BulkBPS : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::BulkBPSConfig BulkBPSConfig - { - get - { - if (!this.Properties.TryGetValue("bulk_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_bps_config"); - } - set { this.Properties["bulk_bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkBPSProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkBPSProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkBPSProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required BulkBPSProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.BulkBPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public BulkBPS() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BulkBPS(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BulkBPS FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkBPSProperties/Cadence.cs b/src/Orb/Models/PriceProperties/BulkBPSProperties/Cadence.cs deleted file mode 100644 index 76cc0468..00000000 --- a/src/Orb/Models/PriceProperties/BulkBPSProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkBPSProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/BulkBPSProperties/ConversionRateConfig.cs deleted file mode 100644 index 33737790..00000000 --- a/src/Orb/Models/PriceProperties/BulkBPSProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.BulkBPSProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BulkBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/BulkBPSProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/BulkBPSProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 5308acca..00000000 --- a/src/Orb/Models/PriceProperties/BulkBPSProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using BulkBPSProperties = Orb.Models.PriceProperties.BulkBPSProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BulkBPSProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : BulkBPSProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : BulkBPSProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkBPSProperties/ModelType.cs b/src/Orb/Models/PriceProperties/BulkBPSProperties/ModelType.cs deleted file mode 100644 index 2bdf4cde..00000000 --- a/src/Orb/Models/PriceProperties/BulkBPSProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkBPS = new("bulk_bps"); - - readonly string _value = value; - - public enum Value - { - BulkBPS, - } - - public Value Known() => - _value switch - { - "bulk_bps" => Value.BulkBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkBPSProperties/PriceType.cs b/src/Orb/Models/PriceProperties/BulkBPSProperties/PriceType.cs deleted file mode 100644 index d1b03ed2..00000000 --- a/src/Orb/Models/PriceProperties/BulkBPSProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkProperties/Cadence.cs b/src/Orb/Models/PriceProperties/BulkProperties/Cadence.cs deleted file mode 100644 index df70b70a..00000000 --- a/src/Orb/Models/PriceProperties/BulkProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/BulkProperties/ConversionRateConfig.cs deleted file mode 100644 index dc62d8f9..00000000 --- a/src/Orb/Models/PriceProperties/BulkProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.BulkProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BulkProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/BulkProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/BulkProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index a711eb50..00000000 --- a/src/Orb/Models/PriceProperties/BulkProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using BulkProperties = Orb.Models.PriceProperties.BulkProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BulkProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : BulkProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : BulkProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkProperties/ModelType.cs b/src/Orb/Models/PriceProperties/BulkProperties/ModelType.cs deleted file mode 100644 index e857d5b0..00000000 --- a/src/Orb/Models/PriceProperties/BulkProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Bulk = new("bulk"); - - readonly string _value = value; - - public enum Value - { - Bulk, - } - - public Value Known() => - _value switch - { - "bulk" => Value.Bulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkProperties/PriceType.cs b/src/Orb/Models/PriceProperties/BulkProperties/PriceType.cs deleted file mode 100644 index fe319ee3..00000000 --- a/src/Orb/Models/PriceProperties/BulkProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkWithProration.cs b/src/Orb/Models/PriceProperties/BulkWithProration.cs deleted file mode 100644 index a07d1038..00000000 --- a/src/Orb/Models/PriceProperties/BulkWithProration.cs +++ /dev/null @@ -1,534 +0,0 @@ -using BulkWithProrationProperties = Orb.Models.PriceProperties.BulkWithProrationProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BulkWithProration : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary BulkWithProrationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "bulk_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "bulk_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("bulk_with_proration_config"); - } - set - { - this.Properties["bulk_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required BulkWithProrationProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkWithProrationProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required BulkWithProrationProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required BulkWithProrationProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - foreach (var item in this.BulkWithProrationConfig.Values) - { - _ = item; - } - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public BulkWithProration() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BulkWithProration(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BulkWithProration FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/Cadence.cs b/src/Orb/Models/PriceProperties/BulkWithProrationProperties/Cadence.cs deleted file mode 100644 index 13cf8ce3..00000000 --- a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ConversionRateConfig.cs deleted file mode 100644 index 4ba39b10..00000000 --- a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.BulkWithProrationProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BulkWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8083f2a4..00000000 --- a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using BulkWithProrationProperties = Orb.Models.PriceProperties.BulkWithProrationProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.BulkWithProrationProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : BulkWithProrationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : BulkWithProrationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ModelType.cs b/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ModelType.cs deleted file mode 100644 index 97b927e9..00000000 --- a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkWithProration = new("bulk_with_proration"); - - readonly string _value = value; - - public enum Value - { - BulkWithProration, - } - - public Value Known() => - _value switch - { - "bulk_with_proration" => Value.BulkWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/PriceType.cs b/src/Orb/Models/PriceProperties/BulkWithProrationProperties/PriceType.cs deleted file mode 100644 index e55cedac..00000000 --- a/src/Orb/Models/PriceProperties/BulkWithProrationProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.BulkWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/CumulativeGroupedBulk.cs b/src/Orb/Models/PriceProperties/CumulativeGroupedBulk.cs deleted file mode 100644 index c5d42fd6..00000000 --- a/src/Orb/Models/PriceProperties/CumulativeGroupedBulk.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using CumulativeGroupedBulkProperties = Orb.Models.PriceProperties.CumulativeGroupedBulkProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class CumulativeGroupedBulk - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required CumulativeGroupedBulkProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required CumulativeGroupedBulkProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary CumulativeGroupedBulkConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "cumulative_grouped_bulk_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "cumulative_grouped_bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("cumulative_grouped_bulk_config"); - } - set - { - this.Properties["cumulative_grouped_bulk_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required CumulativeGroupedBulkProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required CumulativeGroupedBulkProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - foreach (var item in this.CumulativeGroupedBulkConfig.Values) - { - _ = item; - } - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public CumulativeGroupedBulk() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - CumulativeGroupedBulk(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static CumulativeGroupedBulk FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/Cadence.cs b/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/Cadence.cs deleted file mode 100644 index 0a3fd001..00000000 --- a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.CumulativeGroupedBulkProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ConversionRateConfig.cs deleted file mode 100644 index be3479ee..00000000 --- a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.CumulativeGroupedBulkProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.CumulativeGroupedBulkProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f1a9d167..00000000 --- a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using CumulativeGroupedBulkProperties = Orb.Models.PriceProperties.CumulativeGroupedBulkProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.CumulativeGroupedBulkProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : CumulativeGroupedBulkProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : CumulativeGroupedBulkProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ModelType.cs b/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ModelType.cs deleted file mode 100644 index ea123de5..00000000 --- a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.CumulativeGroupedBulkProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType CumulativeGroupedBulk = new("cumulative_grouped_bulk"); - - readonly string _value = value; - - public enum Value - { - CumulativeGroupedBulk, - } - - public Value Known() => - _value switch - { - "cumulative_grouped_bulk" => Value.CumulativeGroupedBulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/PriceType.cs b/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/PriceType.cs deleted file mode 100644 index 728fa57b..00000000 --- a/src/Orb/Models/PriceProperties/CumulativeGroupedBulkProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.CumulativeGroupedBulkProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedAllocation.cs b/src/Orb/Models/PriceProperties/GroupedAllocation.cs deleted file mode 100644 index 7bf48028..00000000 --- a/src/Orb/Models/PriceProperties/GroupedAllocation.cs +++ /dev/null @@ -1,534 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using GroupedAllocationProperties = Orb.Models.PriceProperties.GroupedAllocationProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class GroupedAllocation : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedAllocationProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedAllocationProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Generic::Dictionary GroupedAllocationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "grouped_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_allocation_config"); - } - set - { - this.Properties["grouped_allocation_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedAllocationProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedAllocationProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - foreach (var item in this.GroupedAllocationConfig.Values) - { - _ = item; - } - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public GroupedAllocation() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - GroupedAllocation(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static GroupedAllocation FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/Cadence.cs b/src/Orb/Models/PriceProperties/GroupedAllocationProperties/Cadence.cs deleted file mode 100644 index cafb3fb3..00000000 --- a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ConversionRateConfig.cs deleted file mode 100644 index 739e21b9..00000000 --- a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.GroupedAllocationProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 22dacca8..00000000 --- a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using GroupedAllocationProperties = Orb.Models.PriceProperties.GroupedAllocationProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedAllocationProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : GroupedAllocationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : GroupedAllocationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ModelType.cs b/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ModelType.cs deleted file mode 100644 index 0c314bef..00000000 --- a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedAllocation = new("grouped_allocation"); - - readonly string _value = value; - - public enum Value - { - GroupedAllocation, - } - - public Value Known() => - _value switch - { - "grouped_allocation" => Value.GroupedAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/PriceType.cs b/src/Orb/Models/PriceProperties/GroupedAllocationProperties/PriceType.cs deleted file mode 100644 index ac13999c..00000000 --- a/src/Orb/Models/PriceProperties/GroupedAllocationProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTiered.cs b/src/Orb/Models/PriceProperties/GroupedTiered.cs deleted file mode 100644 index f197c098..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTiered.cs +++ /dev/null @@ -1,531 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using GroupedTieredProperties = Orb.Models.PriceProperties.GroupedTieredProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class GroupedTiered : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedTieredProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedTieredProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Generic::Dictionary GroupedTieredConfig - { - get - { - if ( - !this.Properties.TryGetValue("grouped_tiered_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_config"); - } - set - { - this.Properties["grouped_tiered_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedTieredProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedTieredProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - foreach (var item in this.GroupedTieredConfig.Values) - { - _ = item; - } - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public GroupedTiered() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - GroupedTiered(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static GroupedTiered FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredPackage.cs b/src/Orb/Models/PriceProperties/GroupedTieredPackage.cs deleted file mode 100644 index 08174839..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredPackage.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using GroupedTieredPackageProperties = Orb.Models.PriceProperties.GroupedTieredPackageProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class GroupedTieredPackage - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedTieredPackageProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedTieredPackageProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Generic::Dictionary GroupedTieredPackageConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "grouped_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_package_config"); - } - set - { - this.Properties["grouped_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedTieredPackageProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedTieredPackageProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - foreach (var item in this.GroupedTieredPackageConfig.Values) - { - _ = item; - } - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public GroupedTieredPackage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - GroupedTieredPackage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static GroupedTieredPackage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/Cadence.cs b/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/Cadence.cs deleted file mode 100644 index 802981e7..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ConversionRateConfig.cs deleted file mode 100644 index 424c0ae9..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.GroupedTieredPackageProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 4a28a3f1..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using GroupedTieredPackageProperties = Orb.Models.PriceProperties.GroupedTieredPackageProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedTieredPackageProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : GroupedTieredPackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : GroupedTieredPackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ModelType.cs b/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ModelType.cs deleted file mode 100644 index aa00e775..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTieredPackage = new("grouped_tiered_package"); - - readonly string _value = value; - - public enum Value - { - GroupedTieredPackage, - } - - public Value Known() => - _value switch - { - "grouped_tiered_package" => Value.GroupedTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/PriceType.cs b/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/PriceType.cs deleted file mode 100644 index a3624776..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredPackageProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredProperties/Cadence.cs b/src/Orb/Models/PriceProperties/GroupedTieredProperties/Cadence.cs deleted file mode 100644 index c716cdf0..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedTieredProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/GroupedTieredProperties/ConversionRateConfig.cs deleted file mode 100644 index a86b27c4..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.GroupedTieredProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedTieredProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/GroupedTieredProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 7c138f98..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using GroupedTieredProperties = Orb.Models.PriceProperties.GroupedTieredProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedTieredProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : GroupedTieredProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : GroupedTieredProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredProperties/ModelType.cs b/src/Orb/Models/PriceProperties/GroupedTieredProperties/ModelType.cs deleted file mode 100644 index eccf9fb9..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedTieredProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTiered = new("grouped_tiered"); - - readonly string _value = value; - - public enum Value - { - GroupedTiered, - } - - public Value Known() => - _value switch - { - "grouped_tiered" => Value.GroupedTiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedTieredProperties/PriceType.cs b/src/Orb/Models/PriceProperties/GroupedTieredProperties/PriceType.cs deleted file mode 100644 index aac85819..00000000 --- a/src/Orb/Models/PriceProperties/GroupedTieredProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedTieredProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimum.cs b/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimum.cs deleted file mode 100644 index e299d68c..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimum.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using GroupedWithMeteredMinimumProperties = Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class GroupedWithMeteredMinimum - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedWithMeteredMinimumProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedWithMeteredMinimumProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Generic::Dictionary GroupedWithMeteredMinimumConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "grouped_with_metered_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_metered_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_with_metered_minimum_config"); - } - set - { - this.Properties["grouped_with_metered_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedWithMeteredMinimumProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedWithMeteredMinimumProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - foreach (var item in this.GroupedWithMeteredMinimumConfig.Values) - { - _ = item; - } - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public GroupedWithMeteredMinimum() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - GroupedWithMeteredMinimum(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static GroupedWithMeteredMinimum FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/Cadence.cs b/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/Cadence.cs deleted file mode 100644 index 2264b15a..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ConversionRateConfig.cs deleted file mode 100644 index 8841c792..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8b464f66..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using GroupedWithMeteredMinimumProperties = Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : GroupedWithMeteredMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : GroupedWithMeteredMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ModelType.cs b/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ModelType.cs deleted file mode 100644 index 2c5e63ea..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithMeteredMinimum = new( - "grouped_with_metered_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithMeteredMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_metered_minimum" => Value.GroupedWithMeteredMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/PriceType.cs b/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/PriceType.cs deleted file mode 100644 index 7631eafd..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithMeteredMinimumProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedWithMeteredMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimum.cs b/src/Orb/Models/PriceProperties/GroupedWithProratedMinimum.cs deleted file mode 100644 index 41f698c5..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimum.cs +++ /dev/null @@ -1,539 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using GroupedWithProratedMinimumProperties = Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class GroupedWithProratedMinimum - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedWithProratedMinimumProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedWithProratedMinimumProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Generic::Dictionary GroupedWithProratedMinimumConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "grouped_with_prorated_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_prorated_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException("grouped_with_prorated_minimum_config"); - } - set - { - this.Properties["grouped_with_prorated_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required GroupedWithProratedMinimumProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required GroupedWithProratedMinimumProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - foreach (var item in this.GroupedWithProratedMinimumConfig.Values) - { - _ = item; - } - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public GroupedWithProratedMinimum() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - GroupedWithProratedMinimum(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static GroupedWithProratedMinimum FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/Cadence.cs b/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/Cadence.cs deleted file mode 100644 index 767e02fe..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ConversionRateConfig.cs deleted file mode 100644 index 57c0fdd7..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f16ff25f..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using GroupedWithProratedMinimumProperties = Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : GroupedWithProratedMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : GroupedWithProratedMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ModelType.cs b/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ModelType.cs deleted file mode 100644 index 131cfeae..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithProratedMinimum = new( - "grouped_with_prorated_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithProratedMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_prorated_minimum" => Value.GroupedWithProratedMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/PriceType.cs b/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/PriceType.cs deleted file mode 100644 index 307604d8..00000000 --- a/src/Orb/Models/PriceProperties/GroupedWithProratedMinimumProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.GroupedWithProratedMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/Matrix.cs b/src/Orb/Models/PriceProperties/Matrix.cs deleted file mode 100644 index 55bb6f4e..00000000 --- a/src/Orb/Models/PriceProperties/Matrix.cs +++ /dev/null @@ -1,518 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MatrixProperties = Orb.Models.PriceProperties.MatrixProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Matrix : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MatrixProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MatrixProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::MatrixConfig MatrixConfig - { - get - { - if (!this.Properties.TryGetValue("matrix_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_config"); - } - set { this.Properties["matrix_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MatrixProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MatrixProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.MatrixConfig.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public Matrix() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Matrix(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Matrix FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixProperties/Cadence.cs b/src/Orb/Models/PriceProperties/MatrixProperties/Cadence.cs deleted file mode 100644 index 0940ca53..00000000 --- a/src/Orb/Models/PriceProperties/MatrixProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/MatrixProperties/ConversionRateConfig.cs deleted file mode 100644 index a407b509..00000000 --- a/src/Orb/Models/PriceProperties/MatrixProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.MatrixProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MatrixProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/MatrixProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/MatrixProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 8a3b0b55..00000000 --- a/src/Orb/Models/PriceProperties/MatrixProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MatrixProperties = Orb.Models.PriceProperties.MatrixProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MatrixProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : MatrixProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : MatrixProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixProperties/ModelType.cs b/src/Orb/Models/PriceProperties/MatrixProperties/ModelType.cs deleted file mode 100644 index e4630d3a..00000000 --- a/src/Orb/Models/PriceProperties/MatrixProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Matrix = new("matrix"); - - readonly string _value = value; - - public enum Value - { - Matrix, - } - - public Value Known() => - _value switch - { - "matrix" => Value.Matrix, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixProperties/PriceType.cs b/src/Orb/Models/PriceProperties/MatrixProperties/PriceType.cs deleted file mode 100644 index ccc22cc2..00000000 --- a/src/Orb/Models/PriceProperties/MatrixProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithAllocation.cs b/src/Orb/Models/PriceProperties/MatrixWithAllocation.cs deleted file mode 100644 index c0d2c3e6..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithAllocation.cs +++ /dev/null @@ -1,534 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MatrixWithAllocationProperties = Orb.Models.PriceProperties.MatrixWithAllocationProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MatrixWithAllocation - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MatrixWithAllocationProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MatrixWithAllocationProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::MatrixWithAllocationConfig MatrixWithAllocationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "matrix_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_with_allocation_config"); - } - set - { - this.Properties["matrix_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MatrixWithAllocationProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MatrixWithAllocationProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.MatrixWithAllocationConfig.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public MatrixWithAllocation() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MatrixWithAllocation(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static MatrixWithAllocation FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/Cadence.cs b/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/Cadence.cs deleted file mode 100644 index 83ea6381..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ConversionRateConfig.cs deleted file mode 100644 index 047b18b7..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.MatrixWithAllocationProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MatrixWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f59ea313..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MatrixWithAllocationProperties = Orb.Models.PriceProperties.MatrixWithAllocationProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MatrixWithAllocationProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : MatrixWithAllocationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : MatrixWithAllocationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ModelType.cs b/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ModelType.cs deleted file mode 100644 index 4b98b467..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithAllocation = new("matrix_with_allocation"); - - readonly string _value = value; - - public enum Value - { - MatrixWithAllocation, - } - - public Value Known() => - _value switch - { - "matrix_with_allocation" => Value.MatrixWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/PriceType.cs b/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/PriceType.cs deleted file mode 100644 index 9993c7dc..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithAllocationProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithDisplayName.cs b/src/Orb/Models/PriceProperties/MatrixWithDisplayName.cs deleted file mode 100644 index 2d7a262c..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithDisplayName.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MatrixWithDisplayNameProperties = Orb.Models.PriceProperties.MatrixWithDisplayNameProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MatrixWithDisplayName - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MatrixWithDisplayNameProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MatrixWithDisplayNameProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::Dictionary MatrixWithDisplayNameConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "matrix_with_display_name_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_display_name_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("matrix_with_display_name_config"); - } - set - { - this.Properties["matrix_with_display_name_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MatrixWithDisplayNameProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MatrixWithDisplayNameProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - foreach (var item in this.MatrixWithDisplayNameConfig.Values) - { - _ = item; - } - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public MatrixWithDisplayName() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MatrixWithDisplayName(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static MatrixWithDisplayName FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/Cadence.cs b/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/Cadence.cs deleted file mode 100644 index 61c9a5e4..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixWithDisplayNameProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ConversionRateConfig.cs deleted file mode 100644 index e4cfe1c6..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.MatrixWithDisplayNameProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MatrixWithDisplayNameProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 9a401a8f..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MatrixWithDisplayNameProperties = Orb.Models.PriceProperties.MatrixWithDisplayNameProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MatrixWithDisplayNameProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : MatrixWithDisplayNameProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : MatrixWithDisplayNameProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ModelType.cs b/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ModelType.cs deleted file mode 100644 index cd32ab4d..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixWithDisplayNameProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithDisplayName = new("matrix_with_display_name"); - - readonly string _value = value; - - public enum Value - { - MatrixWithDisplayName, - } - - public Value Known() => - _value switch - { - "matrix_with_display_name" => Value.MatrixWithDisplayName, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/PriceType.cs b/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/PriceType.cs deleted file mode 100644 index 6cd6c8a7..00000000 --- a/src/Orb/Models/PriceProperties/MatrixWithDisplayNameProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MatrixWithDisplayNameProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MaxGroupTieredPackage.cs b/src/Orb/Models/PriceProperties/MaxGroupTieredPackage.cs deleted file mode 100644 index fb251eec..00000000 --- a/src/Orb/Models/PriceProperties/MaxGroupTieredPackage.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using MaxGroupTieredPackageProperties = Orb.Models.PriceProperties.MaxGroupTieredPackageProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MaxGroupTieredPackage - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MaxGroupTieredPackageProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MaxGroupTieredPackageProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::Dictionary MaxGroupTieredPackageConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "max_group_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "max_group_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("max_group_tiered_package_config"); - } - set - { - this.Properties["max_group_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required MaxGroupTieredPackageProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required MaxGroupTieredPackageProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - foreach (var item in this.MaxGroupTieredPackageConfig.Values) - { - _ = item; - } - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public MaxGroupTieredPackage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MaxGroupTieredPackage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static MaxGroupTieredPackage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/Cadence.cs b/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/Cadence.cs deleted file mode 100644 index 24586cb9..00000000 --- a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MaxGroupTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ConversionRateConfig.cs deleted file mode 100644 index 47c5fc1b..00000000 --- a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.MaxGroupTieredPackageProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MaxGroupTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 2663ead5..00000000 --- a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MaxGroupTieredPackageProperties = Orb.Models.PriceProperties.MaxGroupTieredPackageProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.MaxGroupTieredPackageProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : MaxGroupTieredPackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : MaxGroupTieredPackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ModelType.cs b/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ModelType.cs deleted file mode 100644 index 091424d8..00000000 --- a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MaxGroupTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MaxGroupTieredPackage = new("max_group_tiered_package"); - - readonly string _value = value; - - public enum Value - { - MaxGroupTieredPackage, - } - - public Value Known() => - _value switch - { - "max_group_tiered_package" => Value.MaxGroupTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/PriceType.cs b/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/PriceType.cs deleted file mode 100644 index faf0f766..00000000 --- a/src/Orb/Models/PriceProperties/MaxGroupTieredPackageProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.MaxGroupTieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/Package.cs b/src/Orb/Models/PriceProperties/Package.cs deleted file mode 100644 index 76acf22d..00000000 --- a/src/Orb/Models/PriceProperties/Package.cs +++ /dev/null @@ -1,520 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using PackageProperties = Orb.Models.PriceProperties.PackageProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Package : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required PackageProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required PackageProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required PackageProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::PackageConfig PackageConfig - { - get - { - if (!this.Properties.TryGetValue("package_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("package_config"); - } - set { this.Properties["package_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required PackageProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - this.PackageConfig.Validate(); - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public Package() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Package(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Package FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageProperties/Cadence.cs b/src/Orb/Models/PriceProperties/PackageProperties/Cadence.cs deleted file mode 100644 index 5031eb9f..00000000 --- a/src/Orb/Models/PriceProperties/PackageProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.PackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/PackageProperties/ConversionRateConfig.cs deleted file mode 100644 index 4243edfa..00000000 --- a/src/Orb/Models/PriceProperties/PackageProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.PackageProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.PackageProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/PackageProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/PackageProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index e7bfb3c5..00000000 --- a/src/Orb/Models/PriceProperties/PackageProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PackageProperties = Orb.Models.PriceProperties.PackageProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.PackageProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : PackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : PackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageProperties/ModelType.cs b/src/Orb/Models/PriceProperties/PackageProperties/ModelType.cs deleted file mode 100644 index 18685d7e..00000000 --- a/src/Orb/Models/PriceProperties/PackageProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.PackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Package = new("package"); - - readonly string _value = value; - - public enum Value - { - Package, - } - - public Value Known() => - _value switch - { - "package" => Value.Package, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageProperties/PriceType.cs b/src/Orb/Models/PriceProperties/PackageProperties/PriceType.cs deleted file mode 100644 index dc147d89..00000000 --- a/src/Orb/Models/PriceProperties/PackageProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.PackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageWithAllocation.cs b/src/Orb/Models/PriceProperties/PackageWithAllocation.cs deleted file mode 100644 index e3f6832c..00000000 --- a/src/Orb/Models/PriceProperties/PackageWithAllocation.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using PackageWithAllocationProperties = Orb.Models.PriceProperties.PackageWithAllocationProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PackageWithAllocation - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required PackageWithAllocationProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required PackageWithAllocationProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required PackageWithAllocationProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::Dictionary PackageWithAllocationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "package_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "package_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("package_with_allocation_config"); - } - set - { - this.Properties["package_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required PackageWithAllocationProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - foreach (var item in this.PackageWithAllocationConfig.Values) - { - _ = item; - } - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.DimensionalPriceConfiguration?.Validate(); - } - - public PackageWithAllocation() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PackageWithAllocation(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PackageWithAllocation FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/Cadence.cs b/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/Cadence.cs deleted file mode 100644 index b838304a..00000000 --- a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.PackageWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ConversionRateConfig.cs deleted file mode 100644 index 97d80934..00000000 --- a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.PackageWithAllocationProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.PackageWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index b636061b..00000000 --- a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PackageWithAllocationProperties = Orb.Models.PriceProperties.PackageWithAllocationProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.PackageWithAllocationProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : PackageWithAllocationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : PackageWithAllocationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ModelType.cs b/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ModelType.cs deleted file mode 100644 index 8f352d0b..00000000 --- a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.PackageWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType PackageWithAllocation = new("package_with_allocation"); - - readonly string _value = value; - - public enum Value - { - PackageWithAllocation, - } - - public Value Known() => - _value switch - { - "package_with_allocation" => Value.PackageWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/PriceType.cs b/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/PriceType.cs deleted file mode 100644 index c5720217..00000000 --- a/src/Orb/Models/PriceProperties/PackageWithAllocationProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.PackageWithAllocationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricing.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricing.cs deleted file mode 100644 index abeea9ae..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricing.cs +++ /dev/null @@ -1,544 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using ScalableMatrixWithTieredPricingProperties = Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ScalableMatrixWithTieredPricing - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required ScalableMatrixWithTieredPricingProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required ScalableMatrixWithTieredPricingProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required ScalableMatrixWithTieredPricingProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required ScalableMatrixWithTieredPricingProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithTieredPricingConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_tiered_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_tiered_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_tiered_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_tiered_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.ScalableMatrixWithTieredPricingConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public ScalableMatrixWithTieredPricing() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ScalableMatrixWithTieredPricing(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ScalableMatrixWithTieredPricing FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/Cadence.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/Cadence.cs deleted file mode 100644 index 83b0b9a5..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ConversionRateConfig.cs deleted file mode 100644 index 1fe2fef8..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index d7fd7a2e..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ScalableMatrixWithTieredPricingProperties = Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : ScalableMatrixWithTieredPricingProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : ScalableMatrixWithTieredPricingProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ModelType.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ModelType.cs deleted file mode 100644 index 31c19527..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithTieredPricing = new( - "scalable_matrix_with_tiered_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithTieredPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_tiered_pricing" => Value.ScalableMatrixWithTieredPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/PriceType.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/PriceType.cs deleted file mode 100644 index 7fcebd0f..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithTieredPricingProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithTieredPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricing.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricing.cs deleted file mode 100644 index 97b346bd..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricing.cs +++ /dev/null @@ -1,544 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using ScalableMatrixWithUnitPricingProperties = Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ScalableMatrixWithUnitPricing - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required ScalableMatrixWithUnitPricingProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required ScalableMatrixWithUnitPricingProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required ScalableMatrixWithUnitPricingProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required ScalableMatrixWithUnitPricingProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithUnitPricingConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_unit_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_unit_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_unit_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_unit_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.ScalableMatrixWithUnitPricingConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public ScalableMatrixWithUnitPricing() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ScalableMatrixWithUnitPricing(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ScalableMatrixWithUnitPricing FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/Cadence.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/Cadence.cs deleted file mode 100644 index 17ff67ba..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ConversionRateConfig.cs deleted file mode 100644 index 7ccdd530..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f5287d31..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ScalableMatrixWithUnitPricingProperties = Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : ScalableMatrixWithUnitPricingProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : ScalableMatrixWithUnitPricingProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ModelType.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ModelType.cs deleted file mode 100644 index 8ca4bf84..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithUnitPricing = new( - "scalable_matrix_with_unit_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithUnitPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_unit_pricing" => Value.ScalableMatrixWithUnitPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/PriceType.cs b/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/PriceType.cs deleted file mode 100644 index 80c3d7a0..00000000 --- a/src/Orb/Models/PriceProperties/ScalableMatrixWithUnitPricingProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ScalableMatrixWithUnitPricingProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ThresholdTotalAmount.cs b/src/Orb/Models/PriceProperties/ThresholdTotalAmount.cs deleted file mode 100644 index d2528c34..00000000 --- a/src/Orb/Models/PriceProperties/ThresholdTotalAmount.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using ThresholdTotalAmountProperties = Orb.Models.PriceProperties.ThresholdTotalAmountProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ThresholdTotalAmount - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required ThresholdTotalAmountProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required ThresholdTotalAmountProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required ThresholdTotalAmountProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required ThresholdTotalAmountProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary ThresholdTotalAmountConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "threshold_total_amount_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "threshold_total_amount_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("threshold_total_amount_config"); - } - set - { - this.Properties["threshold_total_amount_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.ThresholdTotalAmountConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public ThresholdTotalAmount() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ThresholdTotalAmount(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ThresholdTotalAmount FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/Cadence.cs b/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/Cadence.cs deleted file mode 100644 index 01a29cb8..00000000 --- a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ThresholdTotalAmountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ConversionRateConfig.cs deleted file mode 100644 index 4cf3e6d5..00000000 --- a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.ThresholdTotalAmountProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.ThresholdTotalAmountProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index ef5ac885..00000000 --- a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using ThresholdTotalAmountProperties = Orb.Models.PriceProperties.ThresholdTotalAmountProperties; - -namespace Orb.Models.PriceProperties.ThresholdTotalAmountProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : ThresholdTotalAmountProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : ThresholdTotalAmountProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ModelType.cs b/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ModelType.cs deleted file mode 100644 index 4ccf6ef8..00000000 --- a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ThresholdTotalAmountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ThresholdTotalAmount = new("threshold_total_amount"); - - readonly string _value = value; - - public enum Value - { - ThresholdTotalAmount, - } - - public Value Known() => - _value switch - { - "threshold_total_amount" => Value.ThresholdTotalAmount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/PriceType.cs b/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/PriceType.cs deleted file mode 100644 index 8888e15b..00000000 --- a/src/Orb/Models/PriceProperties/ThresholdTotalAmountProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.ThresholdTotalAmountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/Tiered.cs b/src/Orb/Models/PriceProperties/Tiered.cs deleted file mode 100644 index 61acae33..00000000 --- a/src/Orb/Models/PriceProperties/Tiered.cs +++ /dev/null @@ -1,518 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredProperties = Orb.Models.PriceProperties.TieredProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Tiered : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::TieredConfig TieredConfig - { - get - { - if (!this.Properties.TryGetValue("tiered_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_config"); - } - set { this.Properties["tiered_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.TieredConfig.Validate(); - this.DimensionalPriceConfiguration?.Validate(); - } - - public Tiered() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Tiered(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Tiered FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredBPS.cs b/src/Orb/Models/PriceProperties/TieredBPS.cs deleted file mode 100644 index cd46ebe0..00000000 --- a/src/Orb/Models/PriceProperties/TieredBPS.cs +++ /dev/null @@ -1,523 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredBPSProperties = Orb.Models.PriceProperties.TieredBPSProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredBPS : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredBPSProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredBPSProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredBPSProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredBPSProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::TieredBPSConfig TieredBPSConfig - { - get - { - if (!this.Properties.TryGetValue("tiered_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_bps_config"); - } - set - { - this.Properties["tiered_bps_config"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.TieredBPSConfig.Validate(); - this.DimensionalPriceConfiguration?.Validate(); - } - - public TieredBPS() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredBPS(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredBPS FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredBPSProperties/Cadence.cs b/src/Orb/Models/PriceProperties/TieredBPSProperties/Cadence.cs deleted file mode 100644 index 06836325..00000000 --- a/src/Orb/Models/PriceProperties/TieredBPSProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredBPSProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/TieredBPSProperties/ConversionRateConfig.cs deleted file mode 100644 index 3cd3d281..00000000 --- a/src/Orb/Models/PriceProperties/TieredBPSProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.TieredBPSProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.TieredBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/TieredBPSProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/TieredBPSProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 19983c56..00000000 --- a/src/Orb/Models/PriceProperties/TieredBPSProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TieredBPSProperties = Orb.Models.PriceProperties.TieredBPSProperties; - -namespace Orb.Models.PriceProperties.TieredBPSProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : TieredBPSProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : TieredBPSProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredBPSProperties/ModelType.cs b/src/Orb/Models/PriceProperties/TieredBPSProperties/ModelType.cs deleted file mode 100644 index ea58220b..00000000 --- a/src/Orb/Models/PriceProperties/TieredBPSProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredBPS = new("tiered_bps"); - - readonly string _value = value; - - public enum Value - { - TieredBPS, - } - - public Value Known() => - _value switch - { - "tiered_bps" => Value.TieredBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredBPSProperties/PriceType.cs b/src/Orb/Models/PriceProperties/TieredBPSProperties/PriceType.cs deleted file mode 100644 index 0a90a14a..00000000 --- a/src/Orb/Models/PriceProperties/TieredBPSProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredBPSProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackage.cs b/src/Orb/Models/PriceProperties/TieredPackage.cs deleted file mode 100644 index d3f86789..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackage.cs +++ /dev/null @@ -1,531 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredPackageProperties = Orb.Models.PriceProperties.TieredPackageProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredPackage : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredPackageProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredPackageProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredPackageProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredPackageProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary TieredPackageConfig - { - get - { - if ( - !this.Properties.TryGetValue("tiered_package_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_config"); - } - set - { - this.Properties["tiered_package_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.TieredPackageConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public TieredPackage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredPackage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredPackage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageProperties/Cadence.cs b/src/Orb/Models/PriceProperties/TieredPackageProperties/Cadence.cs deleted file mode 100644 index 2eeadfbf..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/TieredPackageProperties/ConversionRateConfig.cs deleted file mode 100644 index 85ecd4a2..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.TieredPackageProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.TieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/TieredPackageProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 6e11f048..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TieredPackageProperties = Orb.Models.PriceProperties.TieredPackageProperties; - -namespace Orb.Models.PriceProperties.TieredPackageProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : TieredPackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : TieredPackageProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageProperties/ModelType.cs b/src/Orb/Models/PriceProperties/TieredPackageProperties/ModelType.cs deleted file mode 100644 index f211e86e..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackage = new("tiered_package"); - - readonly string _value = value; - - public enum Value - { - TieredPackage, - } - - public Value Known() => - _value switch - { - "tiered_package" => Value.TieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageProperties/PriceType.cs b/src/Orb/Models/PriceProperties/TieredPackageProperties/PriceType.cs deleted file mode 100644 index 99443dae..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredPackageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageWithMinimum.cs b/src/Orb/Models/PriceProperties/TieredPackageWithMinimum.cs deleted file mode 100644 index 594fa016..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageWithMinimum.cs +++ /dev/null @@ -1,538 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredPackageWithMinimumProperties = Orb.Models.PriceProperties.TieredPackageWithMinimumProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredPackageWithMinimum - : Orb::ModelBase, - Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredPackageWithMinimumProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredPackageWithMinimumProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredPackageWithMinimumProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredPackageWithMinimumProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary TieredPackageWithMinimumConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "tiered_package_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_with_minimum_config"); - } - set - { - this.Properties["tiered_package_with_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.TieredPackageWithMinimumConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public TieredPackageWithMinimum() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredPackageWithMinimum(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredPackageWithMinimum FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/Cadence.cs b/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/Cadence.cs deleted file mode 100644 index ebdd3b86..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredPackageWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ConversionRateConfig.cs deleted file mode 100644 index 9e788737..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.TieredPackageWithMinimumProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.TieredPackageWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 003ad8e6..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TieredPackageWithMinimumProperties = Orb.Models.PriceProperties.TieredPackageWithMinimumProperties; - -namespace Orb.Models.PriceProperties.TieredPackageWithMinimumProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : TieredPackageWithMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : TieredPackageWithMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ModelType.cs b/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ModelType.cs deleted file mode 100644 index e3e6e578..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredPackageWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackageWithMinimum = new("tiered_package_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredPackageWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_package_with_minimum" => Value.TieredPackageWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/PriceType.cs b/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/PriceType.cs deleted file mode 100644 index 9e80e0e7..00000000 --- a/src/Orb/Models/PriceProperties/TieredPackageWithMinimumProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredPackageWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredProperties/Cadence.cs b/src/Orb/Models/PriceProperties/TieredProperties/Cadence.cs deleted file mode 100644 index 0abea274..00000000 --- a/src/Orb/Models/PriceProperties/TieredProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/TieredProperties/ConversionRateConfig.cs deleted file mode 100644 index ef1defbf..00000000 --- a/src/Orb/Models/PriceProperties/TieredProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.TieredProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.TieredProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/TieredProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/TieredProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index ff982904..00000000 --- a/src/Orb/Models/PriceProperties/TieredProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TieredProperties = Orb.Models.PriceProperties.TieredProperties; - -namespace Orb.Models.PriceProperties.TieredProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : TieredProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : TieredProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredProperties/ModelType.cs b/src/Orb/Models/PriceProperties/TieredProperties/ModelType.cs deleted file mode 100644 index 846cfadb..00000000 --- a/src/Orb/Models/PriceProperties/TieredProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Tiered = new("tiered"); - - readonly string _value = value; - - public enum Value - { - Tiered, - } - - public Value Known() => - _value switch - { - "tiered" => Value.Tiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredProperties/PriceType.cs b/src/Orb/Models/PriceProperties/TieredProperties/PriceType.cs deleted file mode 100644 index 1310c7b4..00000000 --- a/src/Orb/Models/PriceProperties/TieredProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithMinimum.cs b/src/Orb/Models/PriceProperties/TieredWithMinimum.cs deleted file mode 100644 index ca69b4c9..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithMinimum.cs +++ /dev/null @@ -1,534 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredWithMinimumProperties = Orb.Models.PriceProperties.TieredWithMinimumProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredWithMinimum : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredWithMinimumProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredWithMinimumProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredWithMinimumProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredWithMinimumProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary TieredWithMinimumConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "tiered_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_minimum_config"); - } - set - { - this.Properties["tiered_with_minimum_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.TieredWithMinimumConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public TieredWithMinimum() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredWithMinimum(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredWithMinimum FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/Cadence.cs b/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/Cadence.cs deleted file mode 100644 index 77290f59..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ConversionRateConfig.cs deleted file mode 100644 index 6a9c157f..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.TieredWithMinimumProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.TieredWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 40f4537b..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TieredWithMinimumProperties = Orb.Models.PriceProperties.TieredWithMinimumProperties; - -namespace Orb.Models.PriceProperties.TieredWithMinimumProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : TieredWithMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : TieredWithMinimumProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ModelType.cs b/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ModelType.cs deleted file mode 100644 index 7eebbe88..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithMinimum = new("tiered_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_with_minimum" => Value.TieredWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/PriceType.cs b/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/PriceType.cs deleted file mode 100644 index 47e4a6ce..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithMinimumProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredWithMinimumProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithProration.cs b/src/Orb/Models/PriceProperties/TieredWithProration.cs deleted file mode 100644 index 9613ef4b..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithProration.cs +++ /dev/null @@ -1,535 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredWithProrationProperties = Orb.Models.PriceProperties.TieredWithProrationProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredWithProration : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredWithProrationProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredWithProrationProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required TieredWithProrationProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required TieredWithProrationProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary TieredWithProrationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "tiered_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_proration_config"); - } - set - { - this.Properties["tiered_with_proration_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.TieredWithProrationConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public TieredWithProration() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredWithProration(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredWithProration FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/Cadence.cs b/src/Orb/Models/PriceProperties/TieredWithProrationProperties/Cadence.cs deleted file mode 100644 index c5040cc4..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ConversionRateConfig.cs deleted file mode 100644 index eb14b5e4..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.TieredWithProrationProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.TieredWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index e89a2045..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using TieredWithProrationProperties = Orb.Models.PriceProperties.TieredWithProrationProperties; - -namespace Orb.Models.PriceProperties.TieredWithProrationProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : TieredWithProrationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : TieredWithProrationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ModelType.cs b/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ModelType.cs deleted file mode 100644 index 1c7a1181..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithProration = new("tiered_with_proration"); - - readonly string _value = value; - - public enum Value - { - TieredWithProration, - } - - public Value Known() => - _value switch - { - "tiered_with_proration" => Value.TieredWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/PriceType.cs b/src/Orb/Models/PriceProperties/TieredWithProrationProperties/PriceType.cs deleted file mode 100644 index e6cb2d2b..00000000 --- a/src/Orb/Models/PriceProperties/TieredWithProrationProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.TieredWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/Unit.cs b/src/Orb/Models/PriceProperties/Unit.cs deleted file mode 100644 index 01abd024..00000000 --- a/src/Orb/Models/PriceProperties/Unit.cs +++ /dev/null @@ -1,516 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using UnitProperties = Orb.Models.PriceProperties.UnitProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Unit : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required UnitProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required UnitProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required UnitProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required UnitProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::UnitConfig UnitConfig - { - get - { - if (!this.Properties.TryGetValue("unit_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_config"); - } - set { this.Properties["unit_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - this.UnitConfig.Validate(); - this.DimensionalPriceConfiguration?.Validate(); - } - - public Unit() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Unit(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Unit FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitProperties/Cadence.cs b/src/Orb/Models/PriceProperties/UnitProperties/Cadence.cs deleted file mode 100644 index 4d9ab51e..00000000 --- a/src/Orb/Models/PriceProperties/UnitProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/UnitProperties/ConversionRateConfig.cs deleted file mode 100644 index 8e155e6a..00000000 --- a/src/Orb/Models/PriceProperties/UnitProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.UnitProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.UnitProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/UnitProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/UnitProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index b9f1eade..00000000 --- a/src/Orb/Models/PriceProperties/UnitProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using UnitProperties = Orb.Models.PriceProperties.UnitProperties; - -namespace Orb.Models.PriceProperties.UnitProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : UnitProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : UnitProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitProperties/ModelType.cs b/src/Orb/Models/PriceProperties/UnitProperties/ModelType.cs deleted file mode 100644 index 85d8eaab..00000000 --- a/src/Orb/Models/PriceProperties/UnitProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Unit = new("unit"); - - readonly string _value = value; - - public enum Value - { - Unit, - } - - public Value Known() => - _value switch - { - "unit" => Value.Unit, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitProperties/PriceType.cs b/src/Orb/Models/PriceProperties/UnitProperties/PriceType.cs deleted file mode 100644 index 23243e33..00000000 --- a/src/Orb/Models/PriceProperties/UnitProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithPercent.cs b/src/Orb/Models/PriceProperties/UnitWithPercent.cs deleted file mode 100644 index 31848f63..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithPercent.cs +++ /dev/null @@ -1,534 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using UnitWithPercentProperties = Orb.Models.PriceProperties.UnitWithPercentProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UnitWithPercent : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required UnitWithPercentProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required UnitWithPercentProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required UnitWithPercentProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required UnitWithPercentProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary UnitWithPercentConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "unit_with_percent_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_percent_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_percent_config"); - } - set - { - this.Properties["unit_with_percent_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.UnitWithPercentConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public UnitWithPercent() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UnitWithPercent(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static UnitWithPercent FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/Cadence.cs b/src/Orb/Models/PriceProperties/UnitWithPercentProperties/Cadence.cs deleted file mode 100644 index 7c4ee5de..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitWithPercentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ConversionRateConfig.cs deleted file mode 100644 index fd56fa26..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.UnitWithPercentProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.UnitWithPercentProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 486ae4fc..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using UnitWithPercentProperties = Orb.Models.PriceProperties.UnitWithPercentProperties; - -namespace Orb.Models.PriceProperties.UnitWithPercentProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : UnitWithPercentProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : UnitWithPercentProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ModelType.cs b/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ModelType.cs deleted file mode 100644 index 2ab398bd..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitWithPercentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithPercent = new("unit_with_percent"); - - readonly string _value = value; - - public enum Value - { - UnitWithPercent, - } - - public Value Known() => - _value switch - { - "unit_with_percent" => Value.UnitWithPercent, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/PriceType.cs b/src/Orb/Models/PriceProperties/UnitWithPercentProperties/PriceType.cs deleted file mode 100644 index adf5e46e..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithPercentProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitWithPercentProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithProration.cs b/src/Orb/Models/PriceProperties/UnitWithProration.cs deleted file mode 100644 index 97447fff..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithProration.cs +++ /dev/null @@ -1,534 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using UnitWithProrationProperties = Orb.Models.PriceProperties.UnitWithProrationProperties; - -namespace Orb.Models.PriceProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UnitWithProration : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillableMetricTiny? BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::BillingCycleConfiguration BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billing_cycle_configuration"); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required UnitWithProrationProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required UnitWithProrationProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Allocation? CreditAllocation - { - get - { - if (!this.Properties.TryGetValue("credit_allocation", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "credit_allocation", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["credit_allocation"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Discount? Discount - { - get - { - if (!this.Properties.TryGetValue("discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "fixed_price_quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required Models::BillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "invoicing_cycle_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Models::ItemSlim Item - { - get - { - if (!this.Properties.TryGetValue("item", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("item", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item"); - } - set { this.Properties["item"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Maximum? Maximum - { - get - { - if (!this.Properties.TryGetValue("maximum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// User specified key-value pairs for the resource. If not present, this defaults - /// to an empty dictionary. Individual keys can be removed by setting the value - /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` - /// to `null`. - /// - public required Generic::Dictionary Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::Minimum? Minimum - { - get - { - if (!this.Properties.TryGetValue("minimum", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required UnitWithProrationProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required UnitWithProrationProperties::PriceType PriceType - { - get - { - if (!this.Properties.TryGetValue("price_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_type"); - } - set { this.Properties["price_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The price id this price replaces. This price will take the place of the replaced - /// price in plan version migrations. - /// - public required string? ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required Generic::Dictionary UnitWithProrationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "unit_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_proration_config"); - } - set - { - this.Properties["unit_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public Models::DimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.ID; - this.BillableMetric?.Validate(); - this.BillingCycleConfiguration.Validate(); - this.Cadence.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.CreatedAt; - this.CreditAllocation?.Validate(); - _ = this.Currency; - this.Discount?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - this.InvoicingCycleConfiguration?.Validate(); - this.Item.Validate(); - this.Maximum?.Validate(); - _ = this.MaximumAmount; - foreach (var item in this.Metadata.Values) - { - _ = item; - } - this.Minimum?.Validate(); - _ = this.MinimumAmount; - this.ModelType.Validate(); - _ = this.Name; - _ = this.PlanPhaseOrder; - this.PriceType.Validate(); - _ = this.ReplacesPriceID; - foreach (var item in this.UnitWithProrationConfig.Values) - { - _ = item; - } - this.DimensionalPriceConfiguration?.Validate(); - } - - public UnitWithProration() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UnitWithProration(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static UnitWithProration FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/Cadence.cs b/src/Orb/Models/PriceProperties/UnitWithProrationProperties/Cadence.cs deleted file mode 100644 index 13fda958..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/Cadence.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - OneTime, - Monthly, - Quarterly, - SemiAnnual, - Annual, - Custom, - } - - public Value Known() => - _value switch - { - "one_time" => Value.OneTime, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "semi_annual" => Value.SemiAnnual, - "annual" => Value.Annual, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ConversionRateConfig.cs b/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ConversionRateConfig.cs deleted file mode 100644 index b1277b12..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.PriceProperties.UnitWithProrationProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceProperties.UnitWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 7ed5b917..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using UnitWithProrationProperties = Orb.Models.PriceProperties.UnitWithProrationProperties; - -namespace Orb.Models.PriceProperties.UnitWithProrationProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : UnitWithProrationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : UnitWithProrationProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ModelType.cs b/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ModelType.cs deleted file mode 100644 index 76793b1f..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithProration = new("unit_with_proration"); - - readonly string _value = value; - - public enum Value - { - UnitWithProration, - } - - public Value Known() => - _value switch - { - "unit_with_proration" => Value.UnitWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/PriceType.cs b/src/Orb/Models/PriceProperties/UnitWithProrationProperties/PriceType.cs deleted file mode 100644 index 4cea6b5a..00000000 --- a/src/Orb/Models/PriceProperties/UnitWithProrationProperties/PriceType.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.PriceProperties.UnitWithProrationProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class PriceType(string value) : Orb::IEnum -{ - public static readonly PriceType UsagePrice = new("usage_price"); - - public static readonly PriceType FixedPrice = new("fixed_price"); - - readonly string _value = value; - - public enum Value - { - UsagePrice, - FixedPrice, - } - - public Value Known() => - _value switch - { - "usage_price" => Value.UsagePrice, - "fixed_price" => Value.FixedPrice, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static PriceType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/PriceVariants/All.cs b/src/Orb/Models/PriceVariants/All.cs deleted file mode 100644 index 0e04b679..00000000 --- a/src/Orb/Models/PriceVariants/All.cs +++ /dev/null @@ -1,524 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceProperties = Orb.Models.PriceProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.PriceVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Unit(PriceProperties::Unit Value) - : Models::Price, - Orb::IVariant -{ - public static Unit From(PriceProperties::Unit value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Package(PriceProperties::Package Value) - : Models::Price, - Orb::IVariant -{ - public static Package From(PriceProperties::Package value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Matrix(PriceProperties::Matrix Value) - : Models::Price, - Orb::IVariant -{ - public static Matrix From(PriceProperties::Matrix value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Tiered(PriceProperties::Tiered Value) - : Models::Price, - Orb::IVariant -{ - public static Tiered From(PriceProperties::Tiered value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class TieredBPS(PriceProperties::TieredBPS Value) - : Models::Price, - Orb::IVariant -{ - public static TieredBPS From(PriceProperties::TieredBPS value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class BPS(PriceProperties::BPS Value) - : Models::Price, - Orb::IVariant -{ - public static BPS From(PriceProperties::BPS value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class BulkBPS(PriceProperties::BulkBPS Value) - : Models::Price, - Orb::IVariant -{ - public static BulkBPS From(PriceProperties::BulkBPS value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Bulk(PriceProperties::Bulk Value) - : Models::Price, - Orb::IVariant -{ - public static Bulk From(PriceProperties::Bulk value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class ThresholdTotalAmount(PriceProperties::ThresholdTotalAmount Value) - : Models::Price, - Orb::IVariant -{ - public static ThresholdTotalAmount From(PriceProperties::ThresholdTotalAmount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredPackage(PriceProperties::TieredPackage Value) - : Models::Price, - Orb::IVariant -{ - public static TieredPackage From(PriceProperties::TieredPackage value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class GroupedTiered(PriceProperties::GroupedTiered Value) - : Models::Price, - Orb::IVariant -{ - public static GroupedTiered From(PriceProperties::GroupedTiered value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredWithMinimum(PriceProperties::TieredWithMinimum Value) - : Models::Price, - Orb::IVariant -{ - public static TieredWithMinimum From(PriceProperties::TieredWithMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - TieredPackageWithMinimum, - PriceProperties::TieredPackageWithMinimum - >) -)] -public sealed record class TieredPackageWithMinimum(PriceProperties::TieredPackageWithMinimum Value) - : Models::Price, - Orb::IVariant -{ - public static TieredPackageWithMinimum From(PriceProperties::TieredPackageWithMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PackageWithAllocation(PriceProperties::PackageWithAllocation Value) - : Models::Price, - Orb::IVariant -{ - public static PackageWithAllocation From(PriceProperties::PackageWithAllocation value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitWithPercent(PriceProperties::UnitWithPercent Value) - : Models::Price, - Orb::IVariant -{ - public static UnitWithPercent From(PriceProperties::UnitWithPercent value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MatrixWithAllocation(PriceProperties::MatrixWithAllocation Value) - : Models::Price, - Orb::IVariant -{ - public static MatrixWithAllocation From(PriceProperties::MatrixWithAllocation value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredWithProration(PriceProperties::TieredWithProration Value) - : Models::Price, - Orb::IVariant -{ - public static TieredWithProration From(PriceProperties::TieredWithProration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitWithProration(PriceProperties::UnitWithProration Value) - : Models::Price, - Orb::IVariant -{ - public static UnitWithProration From(PriceProperties::UnitWithProration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class GroupedAllocation(PriceProperties::GroupedAllocation Value) - : Models::Price, - Orb::IVariant -{ - public static GroupedAllocation From(PriceProperties::GroupedAllocation value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - GroupedWithProratedMinimum, - PriceProperties::GroupedWithProratedMinimum - >) -)] -public sealed record class GroupedWithProratedMinimum( - PriceProperties::GroupedWithProratedMinimum Value -) - : Models::Price, - Orb::IVariant -{ - public static GroupedWithProratedMinimum From(PriceProperties::GroupedWithProratedMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - GroupedWithMeteredMinimum, - PriceProperties::GroupedWithMeteredMinimum - >) -)] -public sealed record class GroupedWithMeteredMinimum( - PriceProperties::GroupedWithMeteredMinimum Value -) - : Models::Price, - Orb::IVariant -{ - public static GroupedWithMeteredMinimum From(PriceProperties::GroupedWithMeteredMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MatrixWithDisplayName(PriceProperties::MatrixWithDisplayName Value) - : Models::Price, - Orb::IVariant -{ - public static MatrixWithDisplayName From(PriceProperties::MatrixWithDisplayName value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BulkWithProration(PriceProperties::BulkWithProration Value) - : Models::Price, - Orb::IVariant -{ - public static BulkWithProration From(PriceProperties::BulkWithProration value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class GroupedTieredPackage(PriceProperties::GroupedTieredPackage Value) - : Models::Price, - Orb::IVariant -{ - public static GroupedTieredPackage From(PriceProperties::GroupedTieredPackage value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class MaxGroupTieredPackage(PriceProperties::MaxGroupTieredPackage Value) - : Models::Price, - Orb::IVariant -{ - public static MaxGroupTieredPackage From(PriceProperties::MaxGroupTieredPackage value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - ScalableMatrixWithUnitPricing, - PriceProperties::ScalableMatrixWithUnitPricing - >) -)] -public sealed record class ScalableMatrixWithUnitPricing( - PriceProperties::ScalableMatrixWithUnitPricing Value -) - : Models::Price, - Orb::IVariant -{ - public static ScalableMatrixWithUnitPricing From( - PriceProperties::ScalableMatrixWithUnitPricing value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - ScalableMatrixWithTieredPricing, - PriceProperties::ScalableMatrixWithTieredPricing - >) -)] -public sealed record class ScalableMatrixWithTieredPricing( - PriceProperties::ScalableMatrixWithTieredPricing Value -) - : Models::Price, - Orb::IVariant< - ScalableMatrixWithTieredPricing, - PriceProperties::ScalableMatrixWithTieredPricing - > -{ - public static ScalableMatrixWithTieredPricing From( - PriceProperties::ScalableMatrixWithTieredPricing value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class CumulativeGroupedBulk(PriceProperties::CumulativeGroupedBulk Value) - : Models::Price, - Orb::IVariant -{ - public static CumulativeGroupedBulk From(PriceProperties::CumulativeGroupedBulk value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Prices/EvaluatePriceGroup.cs b/src/Orb/Models/Prices/EvaluatePriceGroup.cs index 10c55ef5..68e23e51 100644 --- a/src/Orb/Models/Prices/EvaluatePriceGroup.cs +++ b/src/Orb/Models/Prices/EvaluatePriceGroup.cs @@ -1,53 +1,36 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using EvaluatePriceGroupProperties = Orb.Models.Prices.EvaluatePriceGroupProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Prices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EvaluatePriceGroup : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EvaluatePriceGroup : JsonModel { /// /// The price's output for the group /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// /// The values for the group in the order specified by `grouping_keys` /// - public required Generic::List GroupingValues + public required IReadOnlyList GroupingValues { get { - if (!this.Properties.TryGetValue("grouping_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouping_values"); + return JsonModel.GetNotNullClass>(this.RawData, "grouping_values"); } - set { this.Properties["grouping_values"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "grouping_values", value); } } /// @@ -55,19 +38,11 @@ public required string Amount /// public required double Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } + /// public override void Validate() { _ = this.Amount; @@ -80,18 +55,304 @@ public override void Validate() public EvaluatePriceGroup() { } + public EvaluatePriceGroup(EvaluatePriceGroup evaluatePriceGroup) + : base(evaluatePriceGroup) { } + + public EvaluatePriceGroup(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EvaluatePriceGroup(Generic::Dictionary properties) + [SetsRequiredMembers] + EvaluatePriceGroup(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static EvaluatePriceGroup FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EvaluatePriceGroupFromRaw : IFromRawJson +{ + /// + public EvaluatePriceGroup FromRawUnchecked(IReadOnlyDictionary rawData) => + EvaluatePriceGroup.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupingValueConverter))] +public record class GroupingValue +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupingValue(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public GroupingValue(double value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public GroupingValue(bool value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public GroupingValue(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickString(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickString([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDouble(out var value)) { + /// // `value` is of type `double` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDouble([NotNullWhen(true)] out double? value) + { + value = this.Value as double?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBool(out var value)) { + /// // `value` is of type `bool` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBool([NotNullWhen(true)] out bool? value) + { + value = this.Value as bool?; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (string value) => {...}, + /// (double value) => {...}, + /// (bool value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @string, + System::Action @double, + System::Action @bool + ) + { + switch (this.Value) + { + case string value: + @string(value); + break; + case double value: + @double(value); + break; + case bool value: + @bool(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupingValue" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (string value) => {...}, + /// (double value) => {...}, + /// (bool value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @string, + System::Func @double, + System::Func @bool + ) + { + return this.Value switch + { + string value => @string(value), + double value => @double(value), + bool value => @bool(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupingValue" + ), + }; + } + + public static implicit operator GroupingValue(string value) => new(value); + + public static implicit operator GroupingValue(double value) => new(value); + + public static implicit operator GroupingValue(bool value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of GroupingValue"); + } + } + + public virtual bool Equals(GroupingValue? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupingValueConverter : JsonConverter +{ + public override GroupingValue? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + GroupingValue value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Prices/EvaluatePriceGroupProperties/GroupingValue.cs b/src/Orb/Models/Prices/EvaluatePriceGroupProperties/GroupingValue.cs deleted file mode 100644 index 2f44d603..00000000 --- a/src/Orb/Models/Prices/EvaluatePriceGroupProperties/GroupingValue.cs +++ /dev/null @@ -1,19 +0,0 @@ -using GroupingValueVariants = Orb.Models.Prices.EvaluatePriceGroupProperties.GroupingValueVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.EvaluatePriceGroupProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class GroupingValue -{ - internal GroupingValue() { } - - public static GroupingValueVariants::UnionMember0 Create(string value) => new(value); - - public static GroupingValueVariants::UnionMember1 Create(double value) => new(value); - - public static GroupingValueVariants::UnionMember2 Create(bool value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Prices/EvaluatePriceGroupProperties/GroupingValueVariants/All.cs b/src/Orb/Models/Prices/EvaluatePriceGroupProperties/GroupingValueVariants/All.cs deleted file mode 100644 index abdfb616..00000000 --- a/src/Orb/Models/Prices/EvaluatePriceGroupProperties/GroupingValueVariants/All.cs +++ /dev/null @@ -1,44 +0,0 @@ -using EvaluatePriceGroupProperties = Orb.Models.Prices.EvaluatePriceGroupProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.EvaluatePriceGroupProperties.GroupingValueVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class UnionMember0(string Value) - : EvaluatePriceGroupProperties::GroupingValue, - Orb::IVariant -{ - public static UnionMember0 From(string value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class UnionMember1(double Value) - : EvaluatePriceGroupProperties::GroupingValue, - Orb::IVariant -{ - public static UnionMember1 From(double value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class UnionMember2(bool Value) - : EvaluatePriceGroupProperties::GroupingValue, - Orb::IVariant -{ - public static UnionMember2 From(bool value) - { - return new(value); - } - - public override void Validate() { } -} diff --git a/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParams.cs b/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParams.cs index 7c2a81f8..43493a28 100644 --- a/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParams.cs +++ b/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Prices.ExternalPriceID; @@ -8,27 +12,65 @@ namespace Orb.Models.Prices.ExternalPriceID; /// This endpoint returns a price given an external price id. See the [price creation /// API](/api-reference/price/create-price) for more information about external price aliases. /// -public sealed record class ExternalPriceIDFetchParams : Orb::ParamsBase +public sealed record class ExternalPriceIDFetchParams : ParamsBase { - public required string ExternalPriceID; + public string? ExternalPriceID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public ExternalPriceIDFetchParams() { } + + public ExternalPriceIDFetchParams(ExternalPriceIDFetchParams externalPriceIDFetchParams) + : base(externalPriceIDFetchParams) { } + + public ExternalPriceIDFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPriceIDFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPriceIDFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/external_price_id/{0}", this.ExternalPriceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParams.cs b/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParams.cs index 019b97f2..5a4c73ed 100644 --- a/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParams.cs +++ b/src/Orb/Models/Prices/ExternalPriceID/ExternalPriceIDUpdateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Prices.ExternalPriceID; @@ -11,55 +13,106 @@ namespace Orb.Models.Prices.ExternalPriceID; /// This endpoint allows you to update the `metadata` property on a price. If you /// pass null for the metadata value, it will clear any existing metadata for that price. /// -public sealed record class ExternalPriceIDUpdateParams : Orb::ParamsBase +public sealed record class ExternalPriceIDUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string ExternalPriceID; + public string? ExternalPriceID { get; init; } /// /// User-specified key/value pairs for the resource. Individual keys can be removed /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public ExternalPriceIDUpdateParams() { } + + public ExternalPriceIDUpdateParams(ExternalPriceIDUpdateParams externalPriceIDUpdateParams) + : base(externalPriceIDUpdateParams) + { + this._rawBodyData = [.. externalPriceIDUpdateParams._rawBodyData]; + } + + public ExternalPriceIDUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExternalPriceIDUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static ExternalPriceIDUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/external_price_id/{0}", this.ExternalPriceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Prices/PriceCreateParams.cs b/src/Orb/Models/Prices/PriceCreateParams.cs index 185b694f..86811c01 100644 --- a/src/Orb/Models/Prices/PriceCreateParams.cs +++ b/src/Orb/Models/Prices/PriceCreateParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using PriceCreateParamsProperties = Orb.Models.Prices.PriceCreateParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Prices; @@ -14,52 +17,6428 @@ namespace Orb.Models.Prices; /// associated with a specific plan and can instead be individually added to subscriptions, /// including subscriptions on different plans. /// -/// An `external_price_id` can be optionally specified as an alias to allow ergonomic -/// interaction with prices in the Orb API. +/// An `external_price_id` can be optionally specified as an alias to allow +/// ergonomic interaction with prices in the Orb API. /// -/// See the [Price resource](/product-catalog/price-configuration) for the specification -/// of different price model configurations possible in this endpoint. +/// See the [Price resource](/product-catalog/price-configuration) for the +/// specification of different price model configurations possible in this endpoint. /// -public sealed record class PriceCreateParams : Orb::ParamsBase +public sealed record class PriceCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } + + /// + /// New floating price request body params. + /// + public required Body Body + { + get { return JsonModel.GetNotNullClass(this.RawBodyData, "body"); } + init { JsonModel.Set(this._rawBodyData, "body", value); } + } + + public PriceCreateParams() { } + + public PriceCreateParams(PriceCreateParams priceCreateParams) + : base(priceCreateParams) + { + this._rawBodyData = [.. priceCreateParams._rawBodyData]; + } + + public PriceCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PriceCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/prices") + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +/// +/// New floating price request body params. +/// +[JsonConverter(typeof(BodyConverter))] +public record class Body +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Currency + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.Currency, + newFloatingTieredPrice: (x) => x.Currency, + newFloatingBulkPrice: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newFloatingPackagePrice: (x) => x.Currency, + newFloatingMatrixPrice: (x) => x.Currency, + newFloatingThresholdTotalAmountPrice: (x) => x.Currency, + newFloatingTieredPackagePrice: (x) => x.Currency, + newFloatingTieredWithMinimumPrice: (x) => x.Currency, + newFloatingGroupedTieredPrice: (x) => x.Currency, + newFloatingTieredPackageWithMinimumPrice: (x) => x.Currency, + newFloatingPackageWithAllocationPrice: (x) => x.Currency, + newFloatingUnitWithPercentPrice: (x) => x.Currency, + newFloatingMatrixWithAllocationPrice: (x) => x.Currency, + newFloatingTieredWithProrationPrice: (x) => x.Currency, + newFloatingUnitWithProrationPrice: (x) => x.Currency, + newFloatingGroupedAllocationPrice: (x) => x.Currency, + newFloatingBulkWithProrationPrice: (x) => x.Currency, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.Currency, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newFloatingMatrixWithDisplayNamePrice: (x) => x.Currency, + newFloatingGroupedTieredPackagePrice: (x) => x.Currency, + newFloatingMaxGroupTieredPackagePrice: (x) => x.Currency, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.Currency, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.Currency, + newFloatingCumulativeGroupedBulkPrice: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newFloatingMinimumCompositePrice: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public string ItemID + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.ItemID, + newFloatingTieredPrice: (x) => x.ItemID, + newFloatingBulkPrice: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newFloatingPackagePrice: (x) => x.ItemID, + newFloatingMatrixPrice: (x) => x.ItemID, + newFloatingThresholdTotalAmountPrice: (x) => x.ItemID, + newFloatingTieredPackagePrice: (x) => x.ItemID, + newFloatingTieredWithMinimumPrice: (x) => x.ItemID, + newFloatingGroupedTieredPrice: (x) => x.ItemID, + newFloatingTieredPackageWithMinimumPrice: (x) => x.ItemID, + newFloatingPackageWithAllocationPrice: (x) => x.ItemID, + newFloatingUnitWithPercentPrice: (x) => x.ItemID, + newFloatingMatrixWithAllocationPrice: (x) => x.ItemID, + newFloatingTieredWithProrationPrice: (x) => x.ItemID, + newFloatingUnitWithProrationPrice: (x) => x.ItemID, + newFloatingGroupedAllocationPrice: (x) => x.ItemID, + newFloatingBulkWithProrationPrice: (x) => x.ItemID, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.ItemID, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newFloatingMatrixWithDisplayNamePrice: (x) => x.ItemID, + newFloatingGroupedTieredPackagePrice: (x) => x.ItemID, + newFloatingMaxGroupTieredPackagePrice: (x) => x.ItemID, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.ItemID, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.ItemID, + newFloatingCumulativeGroupedBulkPrice: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newFloatingMinimumCompositePrice: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.Name, + newFloatingTieredPrice: (x) => x.Name, + newFloatingBulkPrice: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newFloatingPackagePrice: (x) => x.Name, + newFloatingMatrixPrice: (x) => x.Name, + newFloatingThresholdTotalAmountPrice: (x) => x.Name, + newFloatingTieredPackagePrice: (x) => x.Name, + newFloatingTieredWithMinimumPrice: (x) => x.Name, + newFloatingGroupedTieredPrice: (x) => x.Name, + newFloatingTieredPackageWithMinimumPrice: (x) => x.Name, + newFloatingPackageWithAllocationPrice: (x) => x.Name, + newFloatingUnitWithPercentPrice: (x) => x.Name, + newFloatingMatrixWithAllocationPrice: (x) => x.Name, + newFloatingTieredWithProrationPrice: (x) => x.Name, + newFloatingUnitWithProrationPrice: (x) => x.Name, + newFloatingGroupedAllocationPrice: (x) => x.Name, + newFloatingBulkWithProrationPrice: (x) => x.Name, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.Name, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newFloatingMatrixWithDisplayNamePrice: (x) => x.Name, + newFloatingGroupedTieredPackagePrice: (x) => x.Name, + newFloatingMaxGroupTieredPackagePrice: (x) => x.Name, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.Name, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.Name, + newFloatingCumulativeGroupedBulkPrice: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newFloatingMinimumCompositePrice: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.BillableMetricID, + newFloatingTieredPrice: (x) => x.BillableMetricID, + newFloatingBulkPrice: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newFloatingPackagePrice: (x) => x.BillableMetricID, + newFloatingMatrixPrice: (x) => x.BillableMetricID, + newFloatingThresholdTotalAmountPrice: (x) => x.BillableMetricID, + newFloatingTieredPackagePrice: (x) => x.BillableMetricID, + newFloatingTieredWithMinimumPrice: (x) => x.BillableMetricID, + newFloatingGroupedTieredPrice: (x) => x.BillableMetricID, + newFloatingTieredPackageWithMinimumPrice: (x) => x.BillableMetricID, + newFloatingPackageWithAllocationPrice: (x) => x.BillableMetricID, + newFloatingUnitWithPercentPrice: (x) => x.BillableMetricID, + newFloatingMatrixWithAllocationPrice: (x) => x.BillableMetricID, + newFloatingTieredWithProrationPrice: (x) => x.BillableMetricID, + newFloatingUnitWithProrationPrice: (x) => x.BillableMetricID, + newFloatingGroupedAllocationPrice: (x) => x.BillableMetricID, + newFloatingBulkWithProrationPrice: (x) => x.BillableMetricID, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.BillableMetricID, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newFloatingMatrixWithDisplayNamePrice: (x) => x.BillableMetricID, + newFloatingGroupedTieredPackagePrice: (x) => x.BillableMetricID, + newFloatingMaxGroupTieredPackagePrice: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.BillableMetricID, + newFloatingCumulativeGroupedBulkPrice: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newFloatingMinimumCompositePrice: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.BilledInAdvance, + newFloatingTieredPrice: (x) => x.BilledInAdvance, + newFloatingBulkPrice: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newFloatingPackagePrice: (x) => x.BilledInAdvance, + newFloatingMatrixPrice: (x) => x.BilledInAdvance, + newFloatingThresholdTotalAmountPrice: (x) => x.BilledInAdvance, + newFloatingTieredPackagePrice: (x) => x.BilledInAdvance, + newFloatingTieredWithMinimumPrice: (x) => x.BilledInAdvance, + newFloatingGroupedTieredPrice: (x) => x.BilledInAdvance, + newFloatingTieredPackageWithMinimumPrice: (x) => x.BilledInAdvance, + newFloatingPackageWithAllocationPrice: (x) => x.BilledInAdvance, + newFloatingUnitWithPercentPrice: (x) => x.BilledInAdvance, + newFloatingMatrixWithAllocationPrice: (x) => x.BilledInAdvance, + newFloatingTieredWithProrationPrice: (x) => x.BilledInAdvance, + newFloatingUnitWithProrationPrice: (x) => x.BilledInAdvance, + newFloatingGroupedAllocationPrice: (x) => x.BilledInAdvance, + newFloatingBulkWithProrationPrice: (x) => x.BilledInAdvance, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.BilledInAdvance, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newFloatingMatrixWithDisplayNamePrice: (x) => x.BilledInAdvance, + newFloatingGroupedTieredPackagePrice: (x) => x.BilledInAdvance, + newFloatingMaxGroupTieredPackagePrice: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.BilledInAdvance, + newFloatingCumulativeGroupedBulkPrice: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingMinimumCompositePrice: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.BillingCycleConfiguration, + newFloatingTieredPrice: (x) => x.BillingCycleConfiguration, + newFloatingBulkPrice: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newFloatingPackagePrice: (x) => x.BillingCycleConfiguration, + newFloatingMatrixPrice: (x) => x.BillingCycleConfiguration, + newFloatingThresholdTotalAmountPrice: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackagePrice: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithMinimumPrice: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTieredPrice: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackageWithMinimumPrice: (x) => x.BillingCycleConfiguration, + newFloatingPackageWithAllocationPrice: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithPercentPrice: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithAllocationPrice: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithProrationPrice: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithProrationPrice: (x) => x.BillingCycleConfiguration, + newFloatingGroupedAllocationPrice: (x) => x.BillingCycleConfiguration, + newFloatingBulkWithProrationPrice: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithDisplayNamePrice: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTieredPackagePrice: (x) => x.BillingCycleConfiguration, + newFloatingMaxGroupTieredPackagePrice: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.BillingCycleConfiguration, + newFloatingCumulativeGroupedBulkPrice: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingMinimumCompositePrice: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.ConversionRate, + newFloatingTieredPrice: (x) => x.ConversionRate, + newFloatingBulkPrice: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newFloatingPackagePrice: (x) => x.ConversionRate, + newFloatingMatrixPrice: (x) => x.ConversionRate, + newFloatingThresholdTotalAmountPrice: (x) => x.ConversionRate, + newFloatingTieredPackagePrice: (x) => x.ConversionRate, + newFloatingTieredWithMinimumPrice: (x) => x.ConversionRate, + newFloatingGroupedTieredPrice: (x) => x.ConversionRate, + newFloatingTieredPackageWithMinimumPrice: (x) => x.ConversionRate, + newFloatingPackageWithAllocationPrice: (x) => x.ConversionRate, + newFloatingUnitWithPercentPrice: (x) => x.ConversionRate, + newFloatingMatrixWithAllocationPrice: (x) => x.ConversionRate, + newFloatingTieredWithProrationPrice: (x) => x.ConversionRate, + newFloatingUnitWithProrationPrice: (x) => x.ConversionRate, + newFloatingGroupedAllocationPrice: (x) => x.ConversionRate, + newFloatingBulkWithProrationPrice: (x) => x.ConversionRate, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.ConversionRate, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newFloatingMatrixWithDisplayNamePrice: (x) => x.ConversionRate, + newFloatingGroupedTieredPackagePrice: (x) => x.ConversionRate, + newFloatingMaxGroupTieredPackagePrice: (x) => x.ConversionRate, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.ConversionRate, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.ConversionRate, + newFloatingCumulativeGroupedBulkPrice: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newFloatingMinimumCompositePrice: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingBulkPrice: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newFloatingPackagePrice: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingThresholdTotalAmountPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackagePrice: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithMinimumPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTieredPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackageWithMinimumPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingPackageWithAllocationPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithPercentPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithAllocationPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithProrationPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithProrationPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedAllocationPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingBulkWithProrationPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithDisplayNamePrice: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTieredPackagePrice: (x) => x.DimensionalPriceConfiguration, + newFloatingMaxGroupTieredPackagePrice: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => + x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => + x.DimensionalPriceConfiguration, + newFloatingCumulativeGroupedBulkPrice: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingMinimumCompositePrice: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.ExternalPriceID, + newFloatingTieredPrice: (x) => x.ExternalPriceID, + newFloatingBulkPrice: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newFloatingPackagePrice: (x) => x.ExternalPriceID, + newFloatingMatrixPrice: (x) => x.ExternalPriceID, + newFloatingThresholdTotalAmountPrice: (x) => x.ExternalPriceID, + newFloatingTieredPackagePrice: (x) => x.ExternalPriceID, + newFloatingTieredWithMinimumPrice: (x) => x.ExternalPriceID, + newFloatingGroupedTieredPrice: (x) => x.ExternalPriceID, + newFloatingTieredPackageWithMinimumPrice: (x) => x.ExternalPriceID, + newFloatingPackageWithAllocationPrice: (x) => x.ExternalPriceID, + newFloatingUnitWithPercentPrice: (x) => x.ExternalPriceID, + newFloatingMatrixWithAllocationPrice: (x) => x.ExternalPriceID, + newFloatingTieredWithProrationPrice: (x) => x.ExternalPriceID, + newFloatingUnitWithProrationPrice: (x) => x.ExternalPriceID, + newFloatingGroupedAllocationPrice: (x) => x.ExternalPriceID, + newFloatingBulkWithProrationPrice: (x) => x.ExternalPriceID, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.ExternalPriceID, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newFloatingMatrixWithDisplayNamePrice: (x) => x.ExternalPriceID, + newFloatingGroupedTieredPackagePrice: (x) => x.ExternalPriceID, + newFloatingMaxGroupTieredPackagePrice: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.ExternalPriceID, + newFloatingCumulativeGroupedBulkPrice: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingMinimumCompositePrice: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.FixedPriceQuantity, + newFloatingTieredPrice: (x) => x.FixedPriceQuantity, + newFloatingBulkPrice: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newFloatingPackagePrice: (x) => x.FixedPriceQuantity, + newFloatingMatrixPrice: (x) => x.FixedPriceQuantity, + newFloatingThresholdTotalAmountPrice: (x) => x.FixedPriceQuantity, + newFloatingTieredPackagePrice: (x) => x.FixedPriceQuantity, + newFloatingTieredWithMinimumPrice: (x) => x.FixedPriceQuantity, + newFloatingGroupedTieredPrice: (x) => x.FixedPriceQuantity, + newFloatingTieredPackageWithMinimumPrice: (x) => x.FixedPriceQuantity, + newFloatingPackageWithAllocationPrice: (x) => x.FixedPriceQuantity, + newFloatingUnitWithPercentPrice: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithAllocationPrice: (x) => x.FixedPriceQuantity, + newFloatingTieredWithProrationPrice: (x) => x.FixedPriceQuantity, + newFloatingUnitWithProrationPrice: (x) => x.FixedPriceQuantity, + newFloatingGroupedAllocationPrice: (x) => x.FixedPriceQuantity, + newFloatingBulkWithProrationPrice: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithDisplayNamePrice: (x) => x.FixedPriceQuantity, + newFloatingGroupedTieredPackagePrice: (x) => x.FixedPriceQuantity, + newFloatingMaxGroupTieredPackagePrice: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.FixedPriceQuantity, + newFloatingCumulativeGroupedBulkPrice: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingMinimumCompositePrice: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.InvoiceGroupingKey, + newFloatingTieredPrice: (x) => x.InvoiceGroupingKey, + newFloatingBulkPrice: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newFloatingPackagePrice: (x) => x.InvoiceGroupingKey, + newFloatingMatrixPrice: (x) => x.InvoiceGroupingKey, + newFloatingThresholdTotalAmountPrice: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackagePrice: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithMinimumPrice: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTieredPrice: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackageWithMinimumPrice: (x) => x.InvoiceGroupingKey, + newFloatingPackageWithAllocationPrice: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithPercentPrice: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithAllocationPrice: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithProrationPrice: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithProrationPrice: (x) => x.InvoiceGroupingKey, + newFloatingGroupedAllocationPrice: (x) => x.InvoiceGroupingKey, + newFloatingBulkWithProrationPrice: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithDisplayNamePrice: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTieredPackagePrice: (x) => x.InvoiceGroupingKey, + newFloatingMaxGroupTieredPackagePrice: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => x.InvoiceGroupingKey, + newFloatingCumulativeGroupedBulkPrice: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingMinimumCompositePrice: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newFloatingUnitPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingBulkPrice: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newFloatingPackagePrice: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingThresholdTotalAmountPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackagePrice: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithMinimumPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTieredPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackageWithMinimumPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingPackageWithAllocationPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithPercentPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithAllocationPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithProrationPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithProrationPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedAllocationPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingBulkWithProrationPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithProratedMinimumPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithMeteredMinimumPrice: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithDisplayNamePrice: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTieredPackagePrice: (x) => x.InvoicingCycleConfiguration, + newFloatingMaxGroupTieredPackagePrice: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricingPrice: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricingPrice: (x) => + x.InvoicingCycleConfiguration, + newFloatingCumulativeGroupedBulkPrice: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingMinimumCompositePrice: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public Body(NewFloatingUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(global::Orb.Models.Prices.BulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingTieredWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body( + global::Orb.Models.Prices.GroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingScalableMatrixWithUnitPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingScalableMatrixWithTieredPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body( + global::Orb.Models.Prices.CumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Body(NewFloatingMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(global::Orb.Models.Prices.Percent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(global::Orb.Models.Prices.EventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Body(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitPrice(out var value)) { + /// // `value` is of type `NewFloatingUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitPrice([NotNullWhen(true)] out NewFloatingUnitPrice? value) + { + value = this.Value as NewFloatingUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPrice(out var value)) { + /// // `value` is of type `NewFloatingTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPrice([NotNullWhen(true)] out NewFloatingTieredPrice? value) + { + value = this.Value as NewFloatingTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulkPrice(out var value)) { + /// // `value` is of type `NewFloatingBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulkPrice([NotNullWhen(true)] out NewFloatingBulkPrice? value) + { + value = this.Value as NewFloatingBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `global::Orb.Models.Prices.BulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out global::Orb.Models.Prices.BulkWithFilters? value + ) + { + value = this.Value as global::Orb.Models.Prices.BulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackagePrice(out var value)) { + /// // `value` is of type `NewFloatingPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackagePrice( + [NotNullWhen(true)] out NewFloatingPackagePrice? value + ) + { + value = this.Value as NewFloatingPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixPrice(out var value)) { + /// // `value` is of type `NewFloatingMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixPrice([NotNullWhen(true)] out NewFloatingMatrixPrice? value) + { + value = this.Value as NewFloatingMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingThresholdTotalAmountPrice(out var value)) { + /// // `value` is of type `NewFloatingThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingThresholdTotalAmountPrice( + [NotNullWhen(true)] out NewFloatingThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewFloatingThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackagePrice(out var value)) { + /// // `value` is of type `NewFloatingTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackagePrice( + [NotNullWhen(true)] out NewFloatingTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithMinimumPrice(out var value)) { + /// // `value` is of type `NewFloatingTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithMinimumPrice( + [NotNullWhen(true)] out NewFloatingTieredWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTieredPrice(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTieredPrice( + [NotNullWhen(true)] out NewFloatingGroupedTieredPrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackageWithMinimumPrice(out var value)) { + /// // `value` is of type `NewFloatingTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackageWithMinimumPrice( + [NotNullWhen(true)] out NewFloatingTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackageWithAllocationPrice(out var value)) { + /// // `value` is of type `NewFloatingPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackageWithAllocationPrice( + [NotNullWhen(true)] out NewFloatingPackageWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithPercentPrice(out var value)) { + /// // `value` is of type `NewFloatingUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithPercentPrice( + [NotNullWhen(true)] out NewFloatingUnitWithPercentPrice? value + ) + { + value = this.Value as NewFloatingUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithAllocationPrice(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithAllocationPrice( + [NotNullWhen(true)] out NewFloatingMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithProrationPrice(out var value)) { + /// // `value` is of type `NewFloatingTieredWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithProrationPrice( + [NotNullWhen(true)] out NewFloatingTieredWithProrationPrice? value + ) + { + value = this.Value as NewFloatingTieredWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithProrationPrice(out var value)) { + /// // `value` is of type `NewFloatingUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithProrationPrice( + [NotNullWhen(true)] out NewFloatingUnitWithProrationPrice? value + ) + { + value = this.Value as NewFloatingUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedAllocationPrice(out var value)) { + /// // `value` is of type `NewFloatingGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedAllocationPrice( + [NotNullWhen(true)] out NewFloatingGroupedAllocationPrice? value + ) + { + value = this.Value as NewFloatingGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulkWithProrationPrice(out var value)) { + /// // `value` is of type `NewFloatingBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulkWithProrationPrice( + [NotNullWhen(true)] out NewFloatingBulkWithProrationPrice? value + ) + { + value = this.Value as NewFloatingBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithProratedMinimumPrice(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithProratedMinimumPrice( + [NotNullWhen(true)] out NewFloatingGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithMeteredMinimumPrice(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithMeteredMinimumPrice( + [NotNullWhen(true)] out NewFloatingGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `global::Orb.Models.Prices.GroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out global::Orb.Models.Prices.GroupedWithMinMaxThresholds? value + ) + { + value = this.Value as global::Orb.Models.Prices.GroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithDisplayNamePrice(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithDisplayNamePrice( + [NotNullWhen(true)] out NewFloatingMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewFloatingMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTieredPackagePrice(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTieredPackagePrice( + [NotNullWhen(true)] out NewFloatingGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMaxGroupTieredPackagePrice(out var value)) { + /// // `value` is of type `NewFloatingMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMaxGroupTieredPackagePrice( + [NotNullWhen(true)] out NewFloatingMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithUnitPricingPrice(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithUnitPricingPrice( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithTieredPricingPrice(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithTieredPricingPrice( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingCumulativeGroupedBulkPrice(out var value)) { + /// // `value` is of type `NewFloatingCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingCumulativeGroupedBulkPrice( + [NotNullWhen(true)] out NewFloatingCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewFloatingCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `global::Orb.Models.Prices.CumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out global::Orb.Models.Prices.CumulativeGroupedAllocation? value + ) + { + value = this.Value as global::Orb.Models.Prices.CumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMinimumCompositePrice(out var value)) { + /// // `value` is of type `NewFloatingMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMinimumCompositePrice( + [NotNullWhen(true)] out NewFloatingMinimumCompositePrice? value + ) + { + value = this.Value as NewFloatingMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `global::Orb.Models.Prices.Percent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out global::Orb.Models.Prices.Percent? value) + { + value = this.Value as global::Orb.Models.Prices.Percent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `global::Orb.Models.Prices.EventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] out global::Orb.Models.Prices.EventOutput? value + ) + { + value = this.Value as global::Orb.Models.Prices.EventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (global::Orb.Models.Prices.BulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Prices.GroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Prices.CumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Prices.Percent value) => {...}, + /// (global::Orb.Models.Prices.EventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newFloatingUnitPrice, + System::Action newFloatingTieredPrice, + System::Action newFloatingBulkPrice, + System::Action bulkWithFilters, + System::Action newFloatingPackagePrice, + System::Action newFloatingMatrixPrice, + System::Action newFloatingThresholdTotalAmountPrice, + System::Action newFloatingTieredPackagePrice, + System::Action newFloatingTieredWithMinimumPrice, + System::Action newFloatingGroupedTieredPrice, + System::Action newFloatingTieredPackageWithMinimumPrice, + System::Action newFloatingPackageWithAllocationPrice, + System::Action newFloatingUnitWithPercentPrice, + System::Action newFloatingMatrixWithAllocationPrice, + System::Action newFloatingTieredWithProrationPrice, + System::Action newFloatingUnitWithProrationPrice, + System::Action newFloatingGroupedAllocationPrice, + System::Action newFloatingBulkWithProrationPrice, + System::Action newFloatingGroupedWithProratedMinimumPrice, + System::Action newFloatingGroupedWithMeteredMinimumPrice, + System::Action groupedWithMinMaxThresholds, + System::Action newFloatingMatrixWithDisplayNamePrice, + System::Action newFloatingGroupedTieredPackagePrice, + System::Action newFloatingMaxGroupTieredPackagePrice, + System::Action newFloatingScalableMatrixWithUnitPricingPrice, + System::Action newFloatingScalableMatrixWithTieredPricingPrice, + System::Action newFloatingCumulativeGroupedBulkPrice, + System::Action cumulativeGroupedAllocation, + System::Action newFloatingMinimumCompositePrice, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewFloatingUnitPrice value: + newFloatingUnitPrice(value); + break; + case NewFloatingTieredPrice value: + newFloatingTieredPrice(value); + break; + case NewFloatingBulkPrice value: + newFloatingBulkPrice(value); + break; + case global::Orb.Models.Prices.BulkWithFilters value: + bulkWithFilters(value); + break; + case NewFloatingPackagePrice value: + newFloatingPackagePrice(value); + break; + case NewFloatingMatrixPrice value: + newFloatingMatrixPrice(value); + break; + case NewFloatingThresholdTotalAmountPrice value: + newFloatingThresholdTotalAmountPrice(value); + break; + case NewFloatingTieredPackagePrice value: + newFloatingTieredPackagePrice(value); + break; + case NewFloatingTieredWithMinimumPrice value: + newFloatingTieredWithMinimumPrice(value); + break; + case NewFloatingGroupedTieredPrice value: + newFloatingGroupedTieredPrice(value); + break; + case NewFloatingTieredPackageWithMinimumPrice value: + newFloatingTieredPackageWithMinimumPrice(value); + break; + case NewFloatingPackageWithAllocationPrice value: + newFloatingPackageWithAllocationPrice(value); + break; + case NewFloatingUnitWithPercentPrice value: + newFloatingUnitWithPercentPrice(value); + break; + case NewFloatingMatrixWithAllocationPrice value: + newFloatingMatrixWithAllocationPrice(value); + break; + case NewFloatingTieredWithProrationPrice value: + newFloatingTieredWithProrationPrice(value); + break; + case NewFloatingUnitWithProrationPrice value: + newFloatingUnitWithProrationPrice(value); + break; + case NewFloatingGroupedAllocationPrice value: + newFloatingGroupedAllocationPrice(value); + break; + case NewFloatingBulkWithProrationPrice value: + newFloatingBulkWithProrationPrice(value); + break; + case NewFloatingGroupedWithProratedMinimumPrice value: + newFloatingGroupedWithProratedMinimumPrice(value); + break; + case NewFloatingGroupedWithMeteredMinimumPrice value: + newFloatingGroupedWithMeteredMinimumPrice(value); + break; + case global::Orb.Models.Prices.GroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewFloatingMatrixWithDisplayNamePrice value: + newFloatingMatrixWithDisplayNamePrice(value); + break; + case NewFloatingGroupedTieredPackagePrice value: + newFloatingGroupedTieredPackagePrice(value); + break; + case NewFloatingMaxGroupTieredPackagePrice value: + newFloatingMaxGroupTieredPackagePrice(value); + break; + case NewFloatingScalableMatrixWithUnitPricingPrice value: + newFloatingScalableMatrixWithUnitPricingPrice(value); + break; + case NewFloatingScalableMatrixWithTieredPricingPrice value: + newFloatingScalableMatrixWithTieredPricingPrice(value); + break; + case NewFloatingCumulativeGroupedBulkPrice value: + newFloatingCumulativeGroupedBulkPrice(value); + break; + case global::Orb.Models.Prices.CumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewFloatingMinimumCompositePrice value: + newFloatingMinimumCompositePrice(value); + break; + case global::Orb.Models.Prices.Percent value: + percent(value); + break; + case global::Orb.Models.Prices.EventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Body"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (global::Orb.Models.Prices.BulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Prices.GroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Prices.CumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Prices.Percent value) => {...}, + /// (global::Orb.Models.Prices.EventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newFloatingUnitPrice, + System::Func newFloatingTieredPrice, + System::Func newFloatingBulkPrice, + System::Func bulkWithFilters, + System::Func newFloatingPackagePrice, + System::Func newFloatingMatrixPrice, + System::Func newFloatingThresholdTotalAmountPrice, + System::Func newFloatingTieredPackagePrice, + System::Func newFloatingTieredWithMinimumPrice, + System::Func newFloatingGroupedTieredPrice, + System::Func< + NewFloatingTieredPackageWithMinimumPrice, + T + > newFloatingTieredPackageWithMinimumPrice, + System::Func< + NewFloatingPackageWithAllocationPrice, + T + > newFloatingPackageWithAllocationPrice, + System::Func newFloatingUnitWithPercentPrice, + System::Func newFloatingMatrixWithAllocationPrice, + System::Func newFloatingTieredWithProrationPrice, + System::Func newFloatingUnitWithProrationPrice, + System::Func newFloatingGroupedAllocationPrice, + System::Func newFloatingBulkWithProrationPrice, + System::Func< + NewFloatingGroupedWithProratedMinimumPrice, + T + > newFloatingGroupedWithProratedMinimumPrice, + System::Func< + NewFloatingGroupedWithMeteredMinimumPrice, + T + > newFloatingGroupedWithMeteredMinimumPrice, + System::Func< + global::Orb.Models.Prices.GroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func< + NewFloatingMatrixWithDisplayNamePrice, + T + > newFloatingMatrixWithDisplayNamePrice, + System::Func newFloatingGroupedTieredPackagePrice, + System::Func< + NewFloatingMaxGroupTieredPackagePrice, + T + > newFloatingMaxGroupTieredPackagePrice, + System::Func< + NewFloatingScalableMatrixWithUnitPricingPrice, + T + > newFloatingScalableMatrixWithUnitPricingPrice, + System::Func< + NewFloatingScalableMatrixWithTieredPricingPrice, + T + > newFloatingScalableMatrixWithTieredPricingPrice, + System::Func< + NewFloatingCumulativeGroupedBulkPrice, + T + > newFloatingCumulativeGroupedBulkPrice, + System::Func< + global::Orb.Models.Prices.CumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newFloatingMinimumCompositePrice, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewFloatingUnitPrice value => newFloatingUnitPrice(value), + NewFloatingTieredPrice value => newFloatingTieredPrice(value), + NewFloatingBulkPrice value => newFloatingBulkPrice(value), + global::Orb.Models.Prices.BulkWithFilters value => bulkWithFilters(value), + NewFloatingPackagePrice value => newFloatingPackagePrice(value), + NewFloatingMatrixPrice value => newFloatingMatrixPrice(value), + NewFloatingThresholdTotalAmountPrice value => newFloatingThresholdTotalAmountPrice( + value + ), + NewFloatingTieredPackagePrice value => newFloatingTieredPackagePrice(value), + NewFloatingTieredWithMinimumPrice value => newFloatingTieredWithMinimumPrice(value), + NewFloatingGroupedTieredPrice value => newFloatingGroupedTieredPrice(value), + NewFloatingTieredPackageWithMinimumPrice value => + newFloatingTieredPackageWithMinimumPrice(value), + NewFloatingPackageWithAllocationPrice value => newFloatingPackageWithAllocationPrice( + value + ), + NewFloatingUnitWithPercentPrice value => newFloatingUnitWithPercentPrice(value), + NewFloatingMatrixWithAllocationPrice value => newFloatingMatrixWithAllocationPrice( + value + ), + NewFloatingTieredWithProrationPrice value => newFloatingTieredWithProrationPrice(value), + NewFloatingUnitWithProrationPrice value => newFloatingUnitWithProrationPrice(value), + NewFloatingGroupedAllocationPrice value => newFloatingGroupedAllocationPrice(value), + NewFloatingBulkWithProrationPrice value => newFloatingBulkWithProrationPrice(value), + NewFloatingGroupedWithProratedMinimumPrice value => + newFloatingGroupedWithProratedMinimumPrice(value), + NewFloatingGroupedWithMeteredMinimumPrice value => + newFloatingGroupedWithMeteredMinimumPrice(value), + global::Orb.Models.Prices.GroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewFloatingMatrixWithDisplayNamePrice value => newFloatingMatrixWithDisplayNamePrice( + value + ), + NewFloatingGroupedTieredPackagePrice value => newFloatingGroupedTieredPackagePrice( + value + ), + NewFloatingMaxGroupTieredPackagePrice value => newFloatingMaxGroupTieredPackagePrice( + value + ), + NewFloatingScalableMatrixWithUnitPricingPrice value => + newFloatingScalableMatrixWithUnitPricingPrice(value), + NewFloatingScalableMatrixWithTieredPricingPrice value => + newFloatingScalableMatrixWithTieredPricingPrice(value), + NewFloatingCumulativeGroupedBulkPrice value => newFloatingCumulativeGroupedBulkPrice( + value + ), + global::Orb.Models.Prices.CumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewFloatingMinimumCompositePrice value => newFloatingMinimumCompositePrice(value), + global::Orb.Models.Prices.Percent value => percent(value), + global::Orb.Models.Prices.EventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Body"), + }; + } + + public static implicit operator Body(NewFloatingUnitPrice value) => new(value); + + public static implicit operator Body(NewFloatingTieredPrice value) => new(value); + + public static implicit operator Body(NewFloatingBulkPrice value) => new(value); + + public static implicit operator Body(global::Orb.Models.Prices.BulkWithFilters value) => + new(value); + + public static implicit operator Body(NewFloatingPackagePrice value) => new(value); + + public static implicit operator Body(NewFloatingMatrixPrice value) => new(value); + + public static implicit operator Body(NewFloatingThresholdTotalAmountPrice value) => new(value); + + public static implicit operator Body(NewFloatingTieredPackagePrice value) => new(value); + + public static implicit operator Body(NewFloatingTieredWithMinimumPrice value) => new(value); + + public static implicit operator Body(NewFloatingGroupedTieredPrice value) => new(value); + + public static implicit operator Body(NewFloatingTieredPackageWithMinimumPrice value) => + new(value); + + public static implicit operator Body(NewFloatingPackageWithAllocationPrice value) => new(value); + + public static implicit operator Body(NewFloatingUnitWithPercentPrice value) => new(value); + + public static implicit operator Body(NewFloatingMatrixWithAllocationPrice value) => new(value); + + public static implicit operator Body(NewFloatingTieredWithProrationPrice value) => new(value); + + public static implicit operator Body(NewFloatingUnitWithProrationPrice value) => new(value); + + public static implicit operator Body(NewFloatingGroupedAllocationPrice value) => new(value); + + public static implicit operator Body(NewFloatingBulkWithProrationPrice value) => new(value); + + public static implicit operator Body(NewFloatingGroupedWithProratedMinimumPrice value) => + new(value); + + public static implicit operator Body(NewFloatingGroupedWithMeteredMinimumPrice value) => + new(value); + + public static implicit operator Body( + global::Orb.Models.Prices.GroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator Body(NewFloatingMatrixWithDisplayNamePrice value) => new(value); + + public static implicit operator Body(NewFloatingGroupedTieredPackagePrice value) => new(value); + + public static implicit operator Body(NewFloatingMaxGroupTieredPackagePrice value) => new(value); + + public static implicit operator Body(NewFloatingScalableMatrixWithUnitPricingPrice value) => + new(value); + + public static implicit operator Body(NewFloatingScalableMatrixWithTieredPricingPrice value) => + new(value); + + public static implicit operator Body(NewFloatingCumulativeGroupedBulkPrice value) => new(value); + + public static implicit operator Body( + global::Orb.Models.Prices.CumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator Body(NewFloatingMinimumCompositePrice value) => new(value); + + public static implicit operator Body(global::Orb.Models.Prices.Percent value) => new(value); + + public static implicit operator Body(global::Orb.Models.Prices.EventOutput value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Body"); + } + this.Switch( + (newFloatingUnitPrice) => newFloatingUnitPrice.Validate(), + (newFloatingTieredPrice) => newFloatingTieredPrice.Validate(), + (newFloatingBulkPrice) => newFloatingBulkPrice.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newFloatingPackagePrice) => newFloatingPackagePrice.Validate(), + (newFloatingMatrixPrice) => newFloatingMatrixPrice.Validate(), + (newFloatingThresholdTotalAmountPrice) => + newFloatingThresholdTotalAmountPrice.Validate(), + (newFloatingTieredPackagePrice) => newFloatingTieredPackagePrice.Validate(), + (newFloatingTieredWithMinimumPrice) => newFloatingTieredWithMinimumPrice.Validate(), + (newFloatingGroupedTieredPrice) => newFloatingGroupedTieredPrice.Validate(), + (newFloatingTieredPackageWithMinimumPrice) => + newFloatingTieredPackageWithMinimumPrice.Validate(), + (newFloatingPackageWithAllocationPrice) => + newFloatingPackageWithAllocationPrice.Validate(), + (newFloatingUnitWithPercentPrice) => newFloatingUnitWithPercentPrice.Validate(), + (newFloatingMatrixWithAllocationPrice) => + newFloatingMatrixWithAllocationPrice.Validate(), + (newFloatingTieredWithProrationPrice) => newFloatingTieredWithProrationPrice.Validate(), + (newFloatingUnitWithProrationPrice) => newFloatingUnitWithProrationPrice.Validate(), + (newFloatingGroupedAllocationPrice) => newFloatingGroupedAllocationPrice.Validate(), + (newFloatingBulkWithProrationPrice) => newFloatingBulkWithProrationPrice.Validate(), + (newFloatingGroupedWithProratedMinimumPrice) => + newFloatingGroupedWithProratedMinimumPrice.Validate(), + (newFloatingGroupedWithMeteredMinimumPrice) => + newFloatingGroupedWithMeteredMinimumPrice.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newFloatingMatrixWithDisplayNamePrice) => + newFloatingMatrixWithDisplayNamePrice.Validate(), + (newFloatingGroupedTieredPackagePrice) => + newFloatingGroupedTieredPackagePrice.Validate(), + (newFloatingMaxGroupTieredPackagePrice) => + newFloatingMaxGroupTieredPackagePrice.Validate(), + (newFloatingScalableMatrixWithUnitPricingPrice) => + newFloatingScalableMatrixWithUnitPricingPrice.Validate(), + (newFloatingScalableMatrixWithTieredPricingPrice) => + newFloatingScalableMatrixWithTieredPricingPrice.Validate(), + (newFloatingCumulativeGroupedBulkPrice) => + newFloatingCumulativeGroupedBulkPrice.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newFloatingMinimumCompositePrice) => newFloatingMinimumCompositePrice.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(Body? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class BodyConverter : JsonConverter +{ + public override Body? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new Body(element); + } + } + } + + public override void Write(Utf8JsonWriter writer, Body value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.BulkWithFilters, + global::Orb.Models.Prices.BulkWithFiltersFromRaw + >) +)] +public sealed record class BulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required global::Orb.Models.Prices.BulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Prices.ConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public BulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public BulkWithFilters(global::Orb.Models.Prices.BulkWithFilters bulkWithFilters) + : base(bulkWithFilters) { } + + public BulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.BulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.BulkWithFiltersConfig, + global::Orb.Models.Prices.BulkWithFiltersConfigFromRaw + >) +)] +public sealed record class BulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithFiltersConfig() { } + + public BulkWithFiltersConfig( + global::Orb.Models.Prices.BulkWithFiltersConfig bulkWithFiltersConfig + ) + : base(bulkWithFiltersConfig) { } + + public BulkWithFiltersConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.BulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.Filter, + global::Orb.Models.Prices.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public Filter() { } + + public Filter(global::Orb.Models.Prices.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.Filter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.Tier, + global::Orb.Models.Prices.TierFromRaw + >) +)] +public sealed record class Tier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public Tier() { } + + public Tier(global::Orb.Models.Prices.Tier tier) + : base(tier) { } + + public Tier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Tier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Tier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class TierFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.Tier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Prices.CadenceConverter))] +public enum Cadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CadenceConverter : JsonConverter +{ + public override global::Orb.Models.Prices.Cadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Prices.Cadence.Annual, + "semi_annual" => global::Orb.Models.Prices.Cadence.SemiAnnual, + "monthly" => global::Orb.Models.Prices.Cadence.Monthly, + "quarterly" => global::Orb.Models.Prices.Cadence.Quarterly, + "one_time" => global::Orb.Models.Prices.Cadence.OneTime, + "custom" => global::Orb.Models.Prices.Cadence.Custom, + _ => (global::Orb.Models.Prices.Cadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.Cadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Prices.Cadence.Annual => "annual", + global::Orb.Models.Prices.Cadence.SemiAnnual => "semi_annual", + global::Orb.Models.Prices.Cadence.Monthly => "monthly", + global::Orb.Models.Prices.Cadence.Quarterly => "quarterly", + global::Orb.Models.Prices.Cadence.OneTime => "one_time", + global::Orb.Models.Prices.Cadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Prices.ConversionRateConfigConverter))] +public record class ConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ConversionRateConfig(SharedUnitConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(SharedTieredConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Prices.ConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.ConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Prices.ConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.ConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Prices.ConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.ConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.GroupedWithMinMaxThresholds, + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public GroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public GroupedWithMinMaxThresholds( + global::Orb.Models.Prices.GroupedWithMinMaxThresholds groupedWithMinMaxThresholds + ) + : base(groupedWithMinMaxThresholds) { } + + public GroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Prices.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.GroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadenceConverter))] +public enum GroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class GroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => global::Orb + .Models + .Prices + .GroupedWithMinMaxThresholdsCadence + .SemiAnnual, + "monthly" => global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Custom, + _ => (global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Annual => "annual", + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Quarterly => + "quarterly", + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfig, + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsConfig : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public GroupedWithMinMaxThresholdsConfig() { } + + public GroupedWithMinMaxThresholdsConfig( + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfig groupedWithMinMaxThresholdsConfig + ) + : base(groupedWithMinMaxThresholdsConfig) { } + + public GroupedWithMinMaxThresholdsConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class GroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.GroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.CumulativeGroupedAllocation, + global::Orb.Models.Prices.CumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required global::Orb.Models.Prices.CumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public CumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public CumulativeGroupedAllocation( + global::Orb.Models.Prices.CumulativeGroupedAllocation cumulativeGroupedAllocation + ) + : base(cumulativeGroupedAllocation) { } + + public CumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Prices.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.CumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Prices.CumulativeGroupedAllocationCadenceConverter))] +public enum CumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.CumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Annual, + "semi_annual" => global::Orb + .Models + .Prices + .CumulativeGroupedAllocationCadence + .SemiAnnual, + "monthly" => global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Monthly, + "quarterly" => global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Quarterly, + "one_time" => global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.OneTime, + "custom" => global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Custom, + _ => (global::Orb.Models.Prices.CumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Annual => "annual", + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Monthly => "monthly", + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Quarterly => + "quarterly", + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.OneTime => "one_time", + global::Orb.Models.Prices.CumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.CumulativeGroupedAllocationConfig, + global::Orb.Models.Prices.CumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationConfig : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public CumulativeGroupedAllocationConfig() { } + + public CumulativeGroupedAllocationConfig( + global::Orb.Models.Prices.CumulativeGroupedAllocationConfig cumulativeGroupedAllocationConfig + ) + : base(cumulativeGroupedAllocationConfig) { } + + public CumulativeGroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Prices.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.CumulativeGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class CumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.CumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.Percent, + global::Orb.Models.Prices.PercentFromRaw + >) +)] +public sealed record class Percent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required global::Orb.Models.Prices.PercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Prices.PercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public Percent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public Percent(global::Orb.Models.Prices.Percent percent) + : base(percent) { } + + public Percent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.Percent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Prices.PercentCadenceConverter))] +public enum PercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PercentCadenceConverter : JsonConverter +{ + public override global::Orb.Models.Prices.PercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Prices.PercentCadence.Annual, + "semi_annual" => global::Orb.Models.Prices.PercentCadence.SemiAnnual, + "monthly" => global::Orb.Models.Prices.PercentCadence.Monthly, + "quarterly" => global::Orb.Models.Prices.PercentCadence.Quarterly, + "one_time" => global::Orb.Models.Prices.PercentCadence.OneTime, + "custom" => global::Orb.Models.Prices.PercentCadence.Custom, + _ => (global::Orb.Models.Prices.PercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.PercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Prices.PercentCadence.Annual => "annual", + global::Orb.Models.Prices.PercentCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Prices.PercentCadence.Monthly => "monthly", + global::Orb.Models.Prices.PercentCadence.Quarterly => "quarterly", + global::Orb.Models.Prices.PercentCadence.OneTime => "one_time", + global::Orb.Models.Prices.PercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.PercentConfig, + global::Orb.Models.Prices.PercentConfigFromRaw + >) +)] +public sealed record class PercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PercentConfig() { } + + public PercentConfig(global::Orb.Models.Prices.PercentConfig percentConfig) + : base(percentConfig) { } + + public PercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PercentConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.PercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Prices.PercentConversionRateConfigConverter))] +public record class PercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Prices.PercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.PercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Prices.PercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PercentConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.PercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Prices.PercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.PercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} - public required PriceCreateParamsProperties::Body Body +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.EventOutput, + global::Orb.Models.Prices.EventOutputFromRaw + >) +)] +public sealed record class EventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence { get { - if (!this.BodyProperties.TryGetValue("body", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("body", "Missing required argument"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("body"); + /// + /// Configuration for event_output pricing + /// + public required global::Orb.Models.Prices.EventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); } - set { this.BodyProperties["body"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public override System::Uri Url(Orb::IOrbClient client) + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/prices") + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get { - Query = this.QueryString(client), - }.Uri; + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } - public Http::StringContent BodyContent() + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Prices.EventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public EventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public EventOutput(global::Orb.Models.Prices.EventOutput eventOutput) + : base(eventOutput) { } + + public EventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.EventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Prices.EventOutputCadenceConverter))] +public enum EventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class EventOutputCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.EventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Prices.EventOutputCadence.Annual, + "semi_annual" => global::Orb.Models.Prices.EventOutputCadence.SemiAnnual, + "monthly" => global::Orb.Models.Prices.EventOutputCadence.Monthly, + "quarterly" => global::Orb.Models.Prices.EventOutputCadence.Quarterly, + "one_time" => global::Orb.Models.Prices.EventOutputCadence.OneTime, + "custom" => global::Orb.Models.Prices.EventOutputCadence.Custom, + _ => (global::Orb.Models.Prices.EventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.EventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Prices.EventOutputCadence.Annual => "annual", + global::Orb.Models.Prices.EventOutputCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Prices.EventOutputCadence.Monthly => "monthly", + global::Orb.Models.Prices.EventOutputCadence.Quarterly => "quarterly", + global::Orb.Models.Prices.EventOutputCadence.OneTime => "one_time", + global::Orb.Models.Prices.EventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options ); } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Prices.EventOutputConfig, + global::Orb.Models.Prices.EventOutputConfigFromRaw + >) +)] +public sealed record class EventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public EventOutputConfig() { } + + public EventOutputConfig(global::Orb.Models.Prices.EventOutputConfig eventOutputConfig) + : base(eventOutputConfig) { } + + public EventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Prices.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class EventOutputConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Prices.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Prices.EventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Prices.EventOutputConversionRateConfigConverter))] +public record class EventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Prices.EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Prices.EventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) +sealed class EventOutputConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Prices.EventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + conversionRateType = null; } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Prices.EventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.EventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Prices/PriceCreateParamsProperties/Body.cs b/src/Orb/Models/Prices/PriceCreateParamsProperties/Body.cs deleted file mode 100644 index 80eefa19..00000000 --- a/src/Orb/Models/Prices/PriceCreateParamsProperties/Body.cs +++ /dev/null @@ -1,123 +0,0 @@ -using BodyVariants = Orb.Models.Prices.PriceCreateParamsProperties.BodyVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Body -{ - internal Body() { } - - public static BodyVariants::NewFloatingUnitPrice Create(Models::NewFloatingUnitPrice value) => - new(value); - - public static BodyVariants::NewFloatingPackagePrice Create( - Models::NewFloatingPackagePrice value - ) => new(value); - - public static BodyVariants::NewFloatingMatrixPrice Create( - Models::NewFloatingMatrixPrice value - ) => new(value); - - public static BodyVariants::NewFloatingMatrixWithAllocationPrice Create( - Models::NewFloatingMatrixWithAllocationPrice value - ) => new(value); - - public static BodyVariants::NewFloatingTieredPrice Create( - Models::NewFloatingTieredPrice value - ) => new(value); - - public static BodyVariants::NewFloatingTieredBPSPrice Create( - Models::NewFloatingTieredBPSPrice value - ) => new(value); - - public static BodyVariants::NewFloatingBPSPrice Create(Models::NewFloatingBPSPrice value) => - new(value); - - public static BodyVariants::NewFloatingBulkBPSPrice Create( - Models::NewFloatingBulkBPSPrice value - ) => new(value); - - public static BodyVariants::NewFloatingBulkPrice Create(Models::NewFloatingBulkPrice value) => - new(value); - - public static BodyVariants::NewFloatingThresholdTotalAmountPrice Create( - Models::NewFloatingThresholdTotalAmountPrice value - ) => new(value); - - public static BodyVariants::NewFloatingTieredPackagePrice Create( - Models::NewFloatingTieredPackagePrice value - ) => new(value); - - public static BodyVariants::NewFloatingGroupedTieredPrice Create( - Models::NewFloatingGroupedTieredPrice value - ) => new(value); - - public static BodyVariants::NewFloatingMaxGroupTieredPackagePrice Create( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) => new(value); - - public static BodyVariants::NewFloatingTieredWithMinimumPrice Create( - Models::NewFloatingTieredWithMinimumPrice value - ) => new(value); - - public static BodyVariants::NewFloatingPackageWithAllocationPrice Create( - Models::NewFloatingPackageWithAllocationPrice value - ) => new(value); - - public static BodyVariants::NewFloatingTieredPackageWithMinimumPrice Create( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) => new(value); - - public static BodyVariants::NewFloatingUnitWithPercentPrice Create( - Models::NewFloatingUnitWithPercentPrice value - ) => new(value); - - public static BodyVariants::NewFloatingTieredWithProrationPrice Create( - Models::NewFloatingTieredWithProrationPrice value - ) => new(value); - - public static BodyVariants::NewFloatingUnitWithProrationPrice Create( - Models::NewFloatingUnitWithProrationPrice value - ) => new(value); - - public static BodyVariants::NewFloatingGroupedAllocationPrice Create( - Models::NewFloatingGroupedAllocationPrice value - ) => new(value); - - public static BodyVariants::NewFloatingGroupedWithProratedMinimumPrice Create( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) => new(value); - - public static BodyVariants::NewFloatingGroupedWithMeteredMinimumPrice Create( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static BodyVariants::NewFloatingMatrixWithDisplayNamePrice Create( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) => new(value); - - public static BodyVariants::NewFloatingBulkWithProrationPrice Create( - Models::NewFloatingBulkWithProrationPrice value - ) => new(value); - - public static BodyVariants::NewFloatingGroupedTieredPackagePrice Create( - Models::NewFloatingGroupedTieredPackagePrice value - ) => new(value); - - public static BodyVariants::NewFloatingScalableMatrixWithUnitPricingPrice Create( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static BodyVariants::NewFloatingScalableMatrixWithTieredPricingPrice Create( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static BodyVariants::NewFloatingCumulativeGroupedBulkPrice Create( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Prices/PriceCreateParamsProperties/BodyVariants/All.cs b/src/Orb/Models/Prices/PriceCreateParamsProperties/BodyVariants/All.cs deleted file mode 100644 index 6d249496..00000000 --- a/src/Orb/Models/Prices/PriceCreateParamsProperties/BodyVariants/All.cs +++ /dev/null @@ -1,685 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceCreateParamsProperties = Orb.Models.Prices.PriceCreateParamsProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceCreateParamsProperties.BodyVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingUnitPrice(Models::NewFloatingUnitPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingUnitPrice From(Models::NewFloatingUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingPackagePrice(Models::NewFloatingPackagePrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingPackagePrice From(Models::NewFloatingPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingMatrixPrice(Models::NewFloatingMatrixPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingMatrixPrice From(Models::NewFloatingMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - >) -)] -public sealed record class NewFloatingMatrixWithAllocationPrice( - Models::NewFloatingMatrixWithAllocationPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - > -{ - public static NewFloatingMatrixWithAllocationPrice From( - Models::NewFloatingMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredPrice(Models::NewFloatingTieredPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingTieredPrice From(Models::NewFloatingTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredBPSPrice(Models::NewFloatingTieredBPSPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingTieredBPSPrice From(Models::NewFloatingTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBPSPrice(Models::NewFloatingBPSPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingBPSPrice From(Models::NewFloatingBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkBPSPrice(Models::NewFloatingBulkBPSPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingBulkBPSPrice From(Models::NewFloatingBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkPrice(Models::NewFloatingBulkPrice Value) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingBulkPrice From(Models::NewFloatingBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - >) -)] -public sealed record class NewFloatingThresholdTotalAmountPrice( - Models::NewFloatingThresholdTotalAmountPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - > -{ - public static NewFloatingThresholdTotalAmountPrice From( - Models::NewFloatingThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackagePrice, - Models::NewFloatingTieredPackagePrice - >) -)] -public sealed record class NewFloatingTieredPackagePrice( - Models::NewFloatingTieredPackagePrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingTieredPackagePrice From(Models::NewFloatingTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPrice, - Models::NewFloatingGroupedTieredPrice - >) -)] -public sealed record class NewFloatingGroupedTieredPrice( - Models::NewFloatingGroupedTieredPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingGroupedTieredPrice From(Models::NewFloatingGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewFloatingMaxGroupTieredPackagePrice( - Models::NewFloatingMaxGroupTieredPackagePrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - > -{ - public static NewFloatingMaxGroupTieredPackagePrice From( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithMinimumPrice, - Models::NewFloatingTieredWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredWithMinimumPrice( - Models::NewFloatingTieredWithMinimumPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingTieredWithMinimumPrice From( - Models::NewFloatingTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - >) -)] -public sealed record class NewFloatingPackageWithAllocationPrice( - Models::NewFloatingPackageWithAllocationPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - > -{ - public static NewFloatingPackageWithAllocationPrice From( - Models::NewFloatingPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredPackageWithMinimumPrice( - Models::NewFloatingTieredPackageWithMinimumPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - > -{ - public static NewFloatingTieredPackageWithMinimumPrice From( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithPercentPrice, - Models::NewFloatingUnitWithPercentPrice - >) -)] -public sealed record class NewFloatingUnitWithPercentPrice( - Models::NewFloatingUnitWithPercentPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingUnitWithPercentPrice From( - Models::NewFloatingUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - >) -)] -public sealed record class NewFloatingTieredWithProrationPrice( - Models::NewFloatingTieredWithProrationPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - > -{ - public static NewFloatingTieredWithProrationPrice From( - Models::NewFloatingTieredWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithProrationPrice, - Models::NewFloatingUnitWithProrationPrice - >) -)] -public sealed record class NewFloatingUnitWithProrationPrice( - Models::NewFloatingUnitWithProrationPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingUnitWithProrationPrice From( - Models::NewFloatingUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedAllocationPrice, - Models::NewFloatingGroupedAllocationPrice - >) -)] -public sealed record class NewFloatingGroupedAllocationPrice( - Models::NewFloatingGroupedAllocationPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingGroupedAllocationPrice From( - Models::NewFloatingGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithProratedMinimumPrice( - Models::NewFloatingGroupedWithProratedMinimumPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - > -{ - public static NewFloatingGroupedWithProratedMinimumPrice From( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithMeteredMinimumPrice( - Models::NewFloatingGroupedWithMeteredMinimumPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - > -{ - public static NewFloatingGroupedWithMeteredMinimumPrice From( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewFloatingMatrixWithDisplayNamePrice( - Models::NewFloatingMatrixWithDisplayNamePrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - > -{ - public static NewFloatingMatrixWithDisplayNamePrice From( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingBulkWithProrationPrice, - Models::NewFloatingBulkWithProrationPrice - >) -)] -public sealed record class NewFloatingBulkWithProrationPrice( - Models::NewFloatingBulkWithProrationPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant -{ - public static NewFloatingBulkWithProrationPrice From( - Models::NewFloatingBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - >) -)] -public sealed record class NewFloatingGroupedTieredPackagePrice( - Models::NewFloatingGroupedTieredPackagePrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - > -{ - public static NewFloatingGroupedTieredPackagePrice From( - Models::NewFloatingGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice( - Models::NewFloatingScalableMatrixWithUnitPricingPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - > -{ - public static NewFloatingScalableMatrixWithUnitPricingPrice From( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice( - Models::NewFloatingScalableMatrixWithTieredPricingPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - > -{ - public static NewFloatingScalableMatrixWithTieredPricingPrice From( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewFloatingCumulativeGroupedBulkPrice( - Models::NewFloatingCumulativeGroupedBulkPrice Value -) - : PriceCreateParamsProperties::Body, - Orb::IVariant< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - > -{ - public static NewFloatingCumulativeGroupedBulkPrice From( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluateMultipleParams.cs b/src/Orb/Models/Prices/PriceEvaluateMultipleParams.cs index 9847c501..d35f9fc4 100644 --- a/src/Orb/Models/Prices/PriceEvaluateMultipleParams.cs +++ b/src/Orb/Models/Prices/PriceEvaluateMultipleParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using PriceEvaluateMultipleParamsProperties = Orb.Models.Prices.PriceEvaluateMultipleParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Prices; @@ -14,160 +17,6578 @@ namespace Orb.Models.Prices; /// using [computed properties](/extensibility/advanced-metrics#computed-properties), /// supporting the following workflows: /// -/// 1. Showing detailed usage and costs to the end customer. 2. Auditing subtotals -/// on invoice line items. +/// 1. Showing detailed usage and costs to the end customer. 2. Auditing subtotals +/// on invoice line items. /// -/// For these workflows, the expressiveness of computed properties in both the filters -/// and grouping is critical. For example, if you'd like to show your customer their -/// usage grouped by hour and another property, you can do so with the following `grouping_keys`: -/// `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd -/// like to examine a customer's usage for a specific property value, you can do -/// so with the following `filter`: `my_property = 'foo' AND my_other_property = 'bar'`. +/// For these workflows, the expressiveness of computed properties in both +/// the filters and grouping is critical. For example, if you'd like to show your +/// customer their usage grouped by hour and another property, you can do so with +/// the following `grouping_keys`: `["hour_floor_timestamp_millis(timestamp_millis)", +/// "my_property"]`. If you'd like to examine a customer's usage for a specific property +/// value, you can do so with the following `filter`: `my_property = 'foo' AND my_other_property +/// = 'bar'`. /// -/// Prices may either reference existing prices in your Orb account or be defined -/// inline in the request body. Up to 100 prices can be evaluated in a single request. +/// Prices may either reference existing prices in your Orb account or be defined +/// inline in the request body. Up to 100 prices can be evaluated in a single request. /// -/// Prices are evaluated on ingested events and the start of the time range must be -/// no more than 100 days ago. To evaluate based off a set of provided events, the -/// [evaluate preview events](/api-reference/price/evaluate-preview-events) endpoint -/// can be used instead. +/// Prices are evaluated on ingested events and the start of the time range +/// must be no more than 100 days ago. To evaluate based off a set of provided events, +/// the [evaluate preview events](/api-reference/price/evaluate-preview-events) endpoint +/// can be used instead. /// -/// Note that this is a POST endpoint rather than a GET endpoint because it employs -/// a JSON body rather than query parameters. +/// Note that this is a POST endpoint rather than a GET endpoint because it +/// employs a JSON body rather than query parameters. /// -public sealed record class PriceEvaluateMultipleParams : Orb::ParamsBase +public sealed record class PriceEvaluateMultipleParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// The exclusive upper bound for event timestamps /// - public required System::DateTime TimeframeEnd + public required System::DateTimeOffset TimeframeEnd { get { - if (!this.BodyProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct( + this.RawBodyData, + "timeframe_end" + ); } + init { JsonModel.Set(this._rawBodyData, "timeframe_end", value); } } /// /// The inclusive lower bound for event timestamps /// - public required System::DateTime TimeframeStart + public required System::DateTimeOffset TimeframeStart { get { - if (!this.BodyProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct( + this.RawBodyData, + "timeframe_start" + ); } + init { JsonModel.Set(this._rawBodyData, "timeframe_start", value); } } /// /// The ID of the customer to which this evaluation is scoped. /// public string? CustomerID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } + } + + /// + /// The external customer ID of the customer to which this evaluation is scoped. + /// + public string? ExternalCustomerID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } + } + + /// + /// List of prices to evaluate (max 100) + /// + public IReadOnlyList? PriceEvaluations { get { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableClass>( + this.RawBodyData, + "price_evaluations" + ); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "price_evaluations", value); + } + } + + public PriceEvaluateMultipleParams() { } + + public PriceEvaluateMultipleParams(PriceEvaluateMultipleParams priceEvaluateMultipleParams) + : base(priceEvaluateMultipleParams) + { + this._rawBodyData = [.. priceEvaluateMultipleParams._rawBodyData]; + } + + public PriceEvaluateMultipleParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluateMultipleParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluateMultipleParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/prices/evaluate") + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } - return Json::JsonSerializer.Deserialize(element); + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } } +} +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceEvaluation : JsonModel +{ /// - /// The external customer ID of the customer to which this evaluation is scoped. + /// The external ID of a price to evaluate that exists in your Orb account. /// - public string? ExternalCustomerID + public string? ExternalPriceID { - get + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// A boolean [computed property](/extensibility/advanced-metrics#computed-properties) + /// used to filter the underlying billable metric + /// + public string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// Properties (or [computed properties](/extensibility/advanced-metrics#computed-properties)) + /// used to group the underlying billable metric + /// + public IReadOnlyList? GroupingKeys + { + get { return JsonModel.GetNullableClass>(this.RawData, "grouping_keys"); } + init { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawData, "grouping_keys", value); } - set + } + + /// + /// New floating price request body params. + /// + public global::Orb.Models.Prices.Price? Price + { + get { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "price" ); } + init { JsonModel.Set(this._rawData, "price", value); } } /// - /// List of prices to evaluate (max 100) + /// The ID of a price to evaluate that exists in your Orb account. /// - public Generic::List? PriceEvaluations + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.ExternalPriceID; + _ = this.Filter; + _ = this.GroupingKeys; + this.Price?.Validate(); + _ = this.PriceID; + } + + public PriceEvaluation() { } + + public PriceEvaluation(PriceEvaluation priceEvaluation) + : base(priceEvaluation) { } + + public PriceEvaluation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluation FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluationFromRaw : IFromRawJson +{ + /// + public PriceEvaluation FromRawUnchecked(IReadOnlyDictionary rawData) => + PriceEvaluation.FromRawUnchecked(rawData); +} + +/// +/// New floating price request body params. +/// +[JsonConverter(typeof(global::Orb.Models.Prices.PriceConverter))] +public record class Price +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Currency { get { - if ( - !this.BodyProperties.TryGetValue("price_evaluations", out Json::JsonElement element) - ) - return null; + return Match( + newFloatingUnit: (x) => x.Currency, + newFloatingTiered: (x) => x.Currency, + newFloatingBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newFloatingPackage: (x) => x.Currency, + newFloatingMatrix: (x) => x.Currency, + newFloatingThresholdTotalAmount: (x) => x.Currency, + newFloatingTieredPackage: (x) => x.Currency, + newFloatingTieredWithMinimum: (x) => x.Currency, + newFloatingGroupedTiered: (x) => x.Currency, + newFloatingTieredPackageWithMinimum: (x) => x.Currency, + newFloatingPackageWithAllocation: (x) => x.Currency, + newFloatingUnitWithPercent: (x) => x.Currency, + newFloatingMatrixWithAllocation: (x) => x.Currency, + newFloatingTieredWithProration: (x) => x.Currency, + newFloatingUnitWithProration: (x) => x.Currency, + newFloatingGroupedAllocation: (x) => x.Currency, + newFloatingBulkWithProration: (x) => x.Currency, + newFloatingGroupedWithProratedMinimum: (x) => x.Currency, + newFloatingGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newFloatingMatrixWithDisplayName: (x) => x.Currency, + newFloatingGroupedTieredPackage: (x) => x.Currency, + newFloatingMaxGroupTieredPackage: (x) => x.Currency, + newFloatingScalableMatrixWithUnitPricing: (x) => x.Currency, + newFloatingScalableMatrixWithTieredPricing: (x) => x.Currency, + newFloatingCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newFloatingMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } - return Json::JsonSerializer.Deserialize?>( - element + public string ItemID + { + get + { + return Match( + newFloatingUnit: (x) => x.ItemID, + newFloatingTiered: (x) => x.ItemID, + newFloatingBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newFloatingPackage: (x) => x.ItemID, + newFloatingMatrix: (x) => x.ItemID, + newFloatingThresholdTotalAmount: (x) => x.ItemID, + newFloatingTieredPackage: (x) => x.ItemID, + newFloatingTieredWithMinimum: (x) => x.ItemID, + newFloatingGroupedTiered: (x) => x.ItemID, + newFloatingTieredPackageWithMinimum: (x) => x.ItemID, + newFloatingPackageWithAllocation: (x) => x.ItemID, + newFloatingUnitWithPercent: (x) => x.ItemID, + newFloatingMatrixWithAllocation: (x) => x.ItemID, + newFloatingTieredWithProration: (x) => x.ItemID, + newFloatingUnitWithProration: (x) => x.ItemID, + newFloatingGroupedAllocation: (x) => x.ItemID, + newFloatingBulkWithProration: (x) => x.ItemID, + newFloatingGroupedWithProratedMinimum: (x) => x.ItemID, + newFloatingGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newFloatingMatrixWithDisplayName: (x) => x.ItemID, + newFloatingGroupedTieredPackage: (x) => x.ItemID, + newFloatingMaxGroupTieredPackage: (x) => x.ItemID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ItemID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ItemID, + newFloatingCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newFloatingMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID ); } - set + } + + public string Name + { + get { - this.BodyProperties["price_evaluations"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newFloatingUnit: (x) => x.Name, + newFloatingTiered: (x) => x.Name, + newFloatingBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newFloatingPackage: (x) => x.Name, + newFloatingMatrix: (x) => x.Name, + newFloatingThresholdTotalAmount: (x) => x.Name, + newFloatingTieredPackage: (x) => x.Name, + newFloatingTieredWithMinimum: (x) => x.Name, + newFloatingGroupedTiered: (x) => x.Name, + newFloatingTieredPackageWithMinimum: (x) => x.Name, + newFloatingPackageWithAllocation: (x) => x.Name, + newFloatingUnitWithPercent: (x) => x.Name, + newFloatingMatrixWithAllocation: (x) => x.Name, + newFloatingTieredWithProration: (x) => x.Name, + newFloatingUnitWithProration: (x) => x.Name, + newFloatingGroupedAllocation: (x) => x.Name, + newFloatingBulkWithProration: (x) => x.Name, + newFloatingGroupedWithProratedMinimum: (x) => x.Name, + newFloatingGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newFloatingMatrixWithDisplayName: (x) => x.Name, + newFloatingGroupedTieredPackage: (x) => x.Name, + newFloatingMaxGroupTieredPackage: (x) => x.Name, + newFloatingScalableMatrixWithUnitPricing: (x) => x.Name, + newFloatingScalableMatrixWithTieredPricing: (x) => x.Name, + newFloatingCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newFloatingMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name ); } } - public override System::Uri Url(Orb::IOrbClient client) + public string? BillableMetricID { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/prices/evaluate") + get { - Query = this.QueryString(client), - }.Uri; + return Match( + newFloatingUnit: (x) => x.BillableMetricID, + newFloatingTiered: (x) => x.BillableMetricID, + newFloatingBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newFloatingPackage: (x) => x.BillableMetricID, + newFloatingMatrix: (x) => x.BillableMetricID, + newFloatingThresholdTotalAmount: (x) => x.BillableMetricID, + newFloatingTieredPackage: (x) => x.BillableMetricID, + newFloatingTieredWithMinimum: (x) => x.BillableMetricID, + newFloatingGroupedTiered: (x) => x.BillableMetricID, + newFloatingTieredPackageWithMinimum: (x) => x.BillableMetricID, + newFloatingPackageWithAllocation: (x) => x.BillableMetricID, + newFloatingUnitWithPercent: (x) => x.BillableMetricID, + newFloatingMatrixWithAllocation: (x) => x.BillableMetricID, + newFloatingTieredWithProration: (x) => x.BillableMetricID, + newFloatingUnitWithProration: (x) => x.BillableMetricID, + newFloatingGroupedAllocation: (x) => x.BillableMetricID, + newFloatingBulkWithProration: (x) => x.BillableMetricID, + newFloatingGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newFloatingGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newFloatingMatrixWithDisplayName: (x) => x.BillableMetricID, + newFloatingGroupedTieredPackage: (x) => x.BillableMetricID, + newFloatingMaxGroupTieredPackage: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newFloatingCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newFloatingMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } } - public Http::StringContent BodyContent() + public bool? BilledInAdvance { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + get + { + return Match( + newFloatingUnit: (x) => x.BilledInAdvance, + newFloatingTiered: (x) => x.BilledInAdvance, + newFloatingBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newFloatingPackage: (x) => x.BilledInAdvance, + newFloatingMatrix: (x) => x.BilledInAdvance, + newFloatingThresholdTotalAmount: (x) => x.BilledInAdvance, + newFloatingTieredPackage: (x) => x.BilledInAdvance, + newFloatingTieredWithMinimum: (x) => x.BilledInAdvance, + newFloatingGroupedTiered: (x) => x.BilledInAdvance, + newFloatingTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newFloatingPackageWithAllocation: (x) => x.BilledInAdvance, + newFloatingUnitWithPercent: (x) => x.BilledInAdvance, + newFloatingMatrixWithAllocation: (x) => x.BilledInAdvance, + newFloatingTieredWithProration: (x) => x.BilledInAdvance, + newFloatingUnitWithProration: (x) => x.BilledInAdvance, + newFloatingGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingBulkWithProration: (x) => x.BilledInAdvance, + newFloatingGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newFloatingGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newFloatingMatrixWithDisplayName: (x) => x.BilledInAdvance, + newFloatingGroupedTieredPackage: (x) => x.BilledInAdvance, + newFloatingMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newFloatingCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.BillingCycleConfiguration, + newFloatingTiered: (x) => x.BillingCycleConfiguration, + newFloatingBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newFloatingPackage: (x) => x.BillingCycleConfiguration, + newFloatingMatrix: (x) => x.BillingCycleConfiguration, + newFloatingThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTiered: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newFloatingPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithPercent: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithProration: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithProration: (x) => x.BillingCycleConfiguration, + newFloatingGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingBulkWithProration: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newFloatingUnit: (x) => x.ConversionRate, + newFloatingTiered: (x) => x.ConversionRate, + newFloatingBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newFloatingPackage: (x) => x.ConversionRate, + newFloatingMatrix: (x) => x.ConversionRate, + newFloatingThresholdTotalAmount: (x) => x.ConversionRate, + newFloatingTieredPackage: (x) => x.ConversionRate, + newFloatingTieredWithMinimum: (x) => x.ConversionRate, + newFloatingGroupedTiered: (x) => x.ConversionRate, + newFloatingTieredPackageWithMinimum: (x) => x.ConversionRate, + newFloatingPackageWithAllocation: (x) => x.ConversionRate, + newFloatingUnitWithPercent: (x) => x.ConversionRate, + newFloatingMatrixWithAllocation: (x) => x.ConversionRate, + newFloatingTieredWithProration: (x) => x.ConversionRate, + newFloatingUnitWithProration: (x) => x.ConversionRate, + newFloatingGroupedAllocation: (x) => x.ConversionRate, + newFloatingBulkWithProration: (x) => x.ConversionRate, + newFloatingGroupedWithProratedMinimum: (x) => x.ConversionRate, + newFloatingGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newFloatingMatrixWithDisplayName: (x) => x.ConversionRate, + newFloatingGroupedTieredPackage: (x) => x.ConversionRate, + newFloatingMaxGroupTieredPackage: (x) => x.ConversionRate, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newFloatingCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newFloatingMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.DimensionalPriceConfiguration, + newFloatingTiered: (x) => x.DimensionalPriceConfiguration, + newFloatingBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newFloatingPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrix: (x) => x.DimensionalPriceConfiguration, + newFloatingThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newFloatingUnit: (x) => x.ExternalPriceID, + newFloatingTiered: (x) => x.ExternalPriceID, + newFloatingBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newFloatingPackage: (x) => x.ExternalPriceID, + newFloatingMatrix: (x) => x.ExternalPriceID, + newFloatingThresholdTotalAmount: (x) => x.ExternalPriceID, + newFloatingTieredPackage: (x) => x.ExternalPriceID, + newFloatingTieredWithMinimum: (x) => x.ExternalPriceID, + newFloatingGroupedTiered: (x) => x.ExternalPriceID, + newFloatingTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newFloatingPackageWithAllocation: (x) => x.ExternalPriceID, + newFloatingUnitWithPercent: (x) => x.ExternalPriceID, + newFloatingMatrixWithAllocation: (x) => x.ExternalPriceID, + newFloatingTieredWithProration: (x) => x.ExternalPriceID, + newFloatingUnitWithProration: (x) => x.ExternalPriceID, + newFloatingGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingBulkWithProration: (x) => x.ExternalPriceID, + newFloatingGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newFloatingGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newFloatingMatrixWithDisplayName: (x) => x.ExternalPriceID, + newFloatingGroupedTieredPackage: (x) => x.ExternalPriceID, + newFloatingMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newFloatingCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public double? FixedPriceQuantity { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get + { + return Match( + newFloatingUnit: (x) => x.FixedPriceQuantity, + newFloatingTiered: (x) => x.FixedPriceQuantity, + newFloatingBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newFloatingPackage: (x) => x.FixedPriceQuantity, + newFloatingMatrix: (x) => x.FixedPriceQuantity, + newFloatingThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newFloatingTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingTieredWithMinimum: (x) => x.FixedPriceQuantity, + newFloatingGroupedTiered: (x) => x.FixedPriceQuantity, + newFloatingTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newFloatingPackageWithAllocation: (x) => x.FixedPriceQuantity, + newFloatingUnitWithPercent: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithAllocation: (x) => x.FixedPriceQuantity, + newFloatingTieredWithProration: (x) => x.FixedPriceQuantity, + newFloatingUnitWithProration: (x) => x.FixedPriceQuantity, + newFloatingGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingBulkWithProration: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newFloatingGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newFloatingCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + newFloatingUnit: (x) => x.InvoiceGroupingKey, + newFloatingTiered: (x) => x.InvoiceGroupingKey, + newFloatingBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newFloatingPackage: (x) => x.InvoiceGroupingKey, + newFloatingMatrix: (x) => x.InvoiceGroupingKey, + newFloatingThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTiered: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newFloatingPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithPercent: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithProration: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithProration: (x) => x.InvoiceGroupingKey, + newFloatingGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingBulkWithProration: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newFloatingCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.InvoicingCycleConfiguration, + newFloatingTiered: (x) => x.InvoicingCycleConfiguration, + newFloatingBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newFloatingPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrix: (x) => x.InvoicingCycleConfiguration, + newFloatingThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); } } + + public Price(NewFloatingUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PriceBulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingTieredWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PriceGroupedWithMinMaxThresholds value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingScalableMatrixWithUnitPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingScalableMatrixWithTieredPricingPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PriceCumulativeGroupedAllocation value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewFloatingMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PricePercent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(PriceEventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnit(out var value)) { + /// // `value` is of type `NewFloatingUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnit([NotNullWhen(true)] out NewFloatingUnitPrice? value) + { + value = this.Value as NewFloatingUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTiered(out var value)) { + /// // `value` is of type `NewFloatingTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTiered([NotNullWhen(true)] out NewFloatingTieredPrice? value) + { + value = this.Value as NewFloatingTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulk(out var value)) { + /// // `value` is of type `NewFloatingBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulk([NotNullWhen(true)] out NewFloatingBulkPrice? value) + { + value = this.Value as NewFloatingBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `PriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters([NotNullWhen(true)] out PriceBulkWithFilters? value) + { + value = this.Value as PriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackage(out var value)) { + /// // `value` is of type `NewFloatingPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackage([NotNullWhen(true)] out NewFloatingPackagePrice? value) + { + value = this.Value as NewFloatingPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrix(out var value)) { + /// // `value` is of type `NewFloatingMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrix([NotNullWhen(true)] out NewFloatingMatrixPrice? value) + { + value = this.Value as NewFloatingMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewFloatingThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingThresholdTotalAmount( + [NotNullWhen(true)] out NewFloatingThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewFloatingThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackage( + [NotNullWhen(true)] out NewFloatingTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithMinimum(out var value)) { + /// // `value` is of type `NewFloatingTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithMinimum( + [NotNullWhen(true)] out NewFloatingTieredWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTiered(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTiered( + [NotNullWhen(true)] out NewFloatingGroupedTieredPrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewFloatingTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackageWithMinimum( + [NotNullWhen(true)] out NewFloatingTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackageWithAllocation(out var value)) { + /// // `value` is of type `NewFloatingPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackageWithAllocation( + [NotNullWhen(true)] out NewFloatingPackageWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithPercent(out var value)) { + /// // `value` is of type `NewFloatingUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithPercent( + [NotNullWhen(true)] out NewFloatingUnitWithPercentPrice? value + ) + { + value = this.Value as NewFloatingUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithAllocation( + [NotNullWhen(true)] out NewFloatingMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithProration(out var value)) { + /// // `value` is of type `NewFloatingTieredWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithProration( + [NotNullWhen(true)] out NewFloatingTieredWithProrationPrice? value + ) + { + value = this.Value as NewFloatingTieredWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithProration(out var value)) { + /// // `value` is of type `NewFloatingUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithProration( + [NotNullWhen(true)] out NewFloatingUnitWithProrationPrice? value + ) + { + value = this.Value as NewFloatingUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedAllocation(out var value)) { + /// // `value` is of type `NewFloatingGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedAllocation( + [NotNullWhen(true)] out NewFloatingGroupedAllocationPrice? value + ) + { + value = this.Value as NewFloatingGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulkWithProration(out var value)) { + /// // `value` is of type `NewFloatingBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulkWithProration( + [NotNullWhen(true)] out NewFloatingBulkWithProrationPrice? value + ) + { + value = this.Value as NewFloatingBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewFloatingGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewFloatingGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `PriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out PriceGroupedWithMinMaxThresholds? value + ) + { + value = this.Value as PriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithDisplayName( + [NotNullWhen(true)] out NewFloatingMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewFloatingMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTieredPackage( + [NotNullWhen(true)] out NewFloatingGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMaxGroupTieredPackage( + [NotNullWhen(true)] out NewFloatingMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewFloatingCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingCumulativeGroupedBulk( + [NotNullWhen(true)] out NewFloatingCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewFloatingCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `PriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out PriceCumulativeGroupedAllocation? value + ) + { + value = this.Value as PriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMinimumComposite(out var value)) { + /// // `value` is of type `NewFloatingMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMinimumComposite( + [NotNullWhen(true)] out NewFloatingMinimumCompositePrice? value + ) + { + value = this.Value as NewFloatingMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `PricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out PricePercent? value) + { + value = this.Value as PricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `PriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput([NotNullWhen(true)] out PriceEventOutput? value) + { + value = this.Value as PriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (PriceBulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (PriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (PriceCumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (PricePercent value) => {...}, + /// (PriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newFloatingUnit, + System::Action newFloatingTiered, + System::Action newFloatingBulk, + System::Action bulkWithFilters, + System::Action newFloatingPackage, + System::Action newFloatingMatrix, + System::Action newFloatingThresholdTotalAmount, + System::Action newFloatingTieredPackage, + System::Action newFloatingTieredWithMinimum, + System::Action newFloatingGroupedTiered, + System::Action newFloatingTieredPackageWithMinimum, + System::Action newFloatingPackageWithAllocation, + System::Action newFloatingUnitWithPercent, + System::Action newFloatingMatrixWithAllocation, + System::Action newFloatingTieredWithProration, + System::Action newFloatingUnitWithProration, + System::Action newFloatingGroupedAllocation, + System::Action newFloatingBulkWithProration, + System::Action newFloatingGroupedWithProratedMinimum, + System::Action newFloatingGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newFloatingMatrixWithDisplayName, + System::Action newFloatingGroupedTieredPackage, + System::Action newFloatingMaxGroupTieredPackage, + System::Action newFloatingScalableMatrixWithUnitPricing, + System::Action newFloatingScalableMatrixWithTieredPricing, + System::Action newFloatingCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newFloatingMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewFloatingUnitPrice value: + newFloatingUnit(value); + break; + case NewFloatingTieredPrice value: + newFloatingTiered(value); + break; + case NewFloatingBulkPrice value: + newFloatingBulk(value); + break; + case PriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewFloatingPackagePrice value: + newFloatingPackage(value); + break; + case NewFloatingMatrixPrice value: + newFloatingMatrix(value); + break; + case NewFloatingThresholdTotalAmountPrice value: + newFloatingThresholdTotalAmount(value); + break; + case NewFloatingTieredPackagePrice value: + newFloatingTieredPackage(value); + break; + case NewFloatingTieredWithMinimumPrice value: + newFloatingTieredWithMinimum(value); + break; + case NewFloatingGroupedTieredPrice value: + newFloatingGroupedTiered(value); + break; + case NewFloatingTieredPackageWithMinimumPrice value: + newFloatingTieredPackageWithMinimum(value); + break; + case NewFloatingPackageWithAllocationPrice value: + newFloatingPackageWithAllocation(value); + break; + case NewFloatingUnitWithPercentPrice value: + newFloatingUnitWithPercent(value); + break; + case NewFloatingMatrixWithAllocationPrice value: + newFloatingMatrixWithAllocation(value); + break; + case NewFloatingTieredWithProrationPrice value: + newFloatingTieredWithProration(value); + break; + case NewFloatingUnitWithProrationPrice value: + newFloatingUnitWithProration(value); + break; + case NewFloatingGroupedAllocationPrice value: + newFloatingGroupedAllocation(value); + break; + case NewFloatingBulkWithProrationPrice value: + newFloatingBulkWithProration(value); + break; + case NewFloatingGroupedWithProratedMinimumPrice value: + newFloatingGroupedWithProratedMinimum(value); + break; + case NewFloatingGroupedWithMeteredMinimumPrice value: + newFloatingGroupedWithMeteredMinimum(value); + break; + case PriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewFloatingMatrixWithDisplayNamePrice value: + newFloatingMatrixWithDisplayName(value); + break; + case NewFloatingGroupedTieredPackagePrice value: + newFloatingGroupedTieredPackage(value); + break; + case NewFloatingMaxGroupTieredPackagePrice value: + newFloatingMaxGroupTieredPackage(value); + break; + case NewFloatingScalableMatrixWithUnitPricingPrice value: + newFloatingScalableMatrixWithUnitPricing(value); + break; + case NewFloatingScalableMatrixWithTieredPricingPrice value: + newFloatingScalableMatrixWithTieredPricing(value); + break; + case NewFloatingCumulativeGroupedBulkPrice value: + newFloatingCumulativeGroupedBulk(value); + break; + case PriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewFloatingMinimumCompositePrice value: + newFloatingMinimumComposite(value); + break; + case PricePercent value: + percent(value); + break; + case PriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (PriceBulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (PriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (PriceCumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (PricePercent value) => {...}, + /// (PriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newFloatingUnit, + System::Func newFloatingTiered, + System::Func newFloatingBulk, + System::Func bulkWithFilters, + System::Func newFloatingPackage, + System::Func newFloatingMatrix, + System::Func newFloatingThresholdTotalAmount, + System::Func newFloatingTieredPackage, + System::Func newFloatingTieredWithMinimum, + System::Func newFloatingGroupedTiered, + System::Func< + NewFloatingTieredPackageWithMinimumPrice, + T + > newFloatingTieredPackageWithMinimum, + System::Func newFloatingPackageWithAllocation, + System::Func newFloatingUnitWithPercent, + System::Func newFloatingMatrixWithAllocation, + System::Func newFloatingTieredWithProration, + System::Func newFloatingUnitWithProration, + System::Func newFloatingGroupedAllocation, + System::Func newFloatingBulkWithProration, + System::Func< + NewFloatingGroupedWithProratedMinimumPrice, + T + > newFloatingGroupedWithProratedMinimum, + System::Func< + NewFloatingGroupedWithMeteredMinimumPrice, + T + > newFloatingGroupedWithMeteredMinimum, + System::Func groupedWithMinMaxThresholds, + System::Func newFloatingMatrixWithDisplayName, + System::Func newFloatingGroupedTieredPackage, + System::Func newFloatingMaxGroupTieredPackage, + System::Func< + NewFloatingScalableMatrixWithUnitPricingPrice, + T + > newFloatingScalableMatrixWithUnitPricing, + System::Func< + NewFloatingScalableMatrixWithTieredPricingPrice, + T + > newFloatingScalableMatrixWithTieredPricing, + System::Func newFloatingCumulativeGroupedBulk, + System::Func cumulativeGroupedAllocation, + System::Func newFloatingMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewFloatingUnitPrice value => newFloatingUnit(value), + NewFloatingTieredPrice value => newFloatingTiered(value), + NewFloatingBulkPrice value => newFloatingBulk(value), + PriceBulkWithFilters value => bulkWithFilters(value), + NewFloatingPackagePrice value => newFloatingPackage(value), + NewFloatingMatrixPrice value => newFloatingMatrix(value), + NewFloatingThresholdTotalAmountPrice value => newFloatingThresholdTotalAmount(value), + NewFloatingTieredPackagePrice value => newFloatingTieredPackage(value), + NewFloatingTieredWithMinimumPrice value => newFloatingTieredWithMinimum(value), + NewFloatingGroupedTieredPrice value => newFloatingGroupedTiered(value), + NewFloatingTieredPackageWithMinimumPrice value => newFloatingTieredPackageWithMinimum( + value + ), + NewFloatingPackageWithAllocationPrice value => newFloatingPackageWithAllocation(value), + NewFloatingUnitWithPercentPrice value => newFloatingUnitWithPercent(value), + NewFloatingMatrixWithAllocationPrice value => newFloatingMatrixWithAllocation(value), + NewFloatingTieredWithProrationPrice value => newFloatingTieredWithProration(value), + NewFloatingUnitWithProrationPrice value => newFloatingUnitWithProration(value), + NewFloatingGroupedAllocationPrice value => newFloatingGroupedAllocation(value), + NewFloatingBulkWithProrationPrice value => newFloatingBulkWithProration(value), + NewFloatingGroupedWithProratedMinimumPrice value => + newFloatingGroupedWithProratedMinimum(value), + NewFloatingGroupedWithMeteredMinimumPrice value => newFloatingGroupedWithMeteredMinimum( + value + ), + PriceGroupedWithMinMaxThresholds value => groupedWithMinMaxThresholds(value), + NewFloatingMatrixWithDisplayNamePrice value => newFloatingMatrixWithDisplayName(value), + NewFloatingGroupedTieredPackagePrice value => newFloatingGroupedTieredPackage(value), + NewFloatingMaxGroupTieredPackagePrice value => newFloatingMaxGroupTieredPackage(value), + NewFloatingScalableMatrixWithUnitPricingPrice value => + newFloatingScalableMatrixWithUnitPricing(value), + NewFloatingScalableMatrixWithTieredPricingPrice value => + newFloatingScalableMatrixWithTieredPricing(value), + NewFloatingCumulativeGroupedBulkPrice value => newFloatingCumulativeGroupedBulk(value), + PriceCumulativeGroupedAllocation value => cumulativeGroupedAllocation(value), + NewFloatingMinimumCompositePrice value => newFloatingMinimumComposite(value), + PricePercent value => percent(value), + PriceEventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Price"), + }; + } + + public static implicit operator global::Orb.Models.Prices.Price(NewFloatingUnitPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Prices.Price(NewFloatingTieredPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Prices.Price(NewFloatingBulkPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Prices.Price(PriceBulkWithFilters value) => + new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price(NewFloatingMatrixPrice value) => + new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingGroupedTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingUnitWithPercentPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingTieredWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingUnitWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingGroupedAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingBulkWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + PriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + PriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price( + NewFloatingMinimumCompositePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Prices.Price(PricePercent value) => + new(value); + + public static implicit operator global::Orb.Models.Prices.Price(PriceEventOutput value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + this.Switch( + (newFloatingUnit) => newFloatingUnit.Validate(), + (newFloatingTiered) => newFloatingTiered.Validate(), + (newFloatingBulk) => newFloatingBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newFloatingPackage) => newFloatingPackage.Validate(), + (newFloatingMatrix) => newFloatingMatrix.Validate(), + (newFloatingThresholdTotalAmount) => newFloatingThresholdTotalAmount.Validate(), + (newFloatingTieredPackage) => newFloatingTieredPackage.Validate(), + (newFloatingTieredWithMinimum) => newFloatingTieredWithMinimum.Validate(), + (newFloatingGroupedTiered) => newFloatingGroupedTiered.Validate(), + (newFloatingTieredPackageWithMinimum) => newFloatingTieredPackageWithMinimum.Validate(), + (newFloatingPackageWithAllocation) => newFloatingPackageWithAllocation.Validate(), + (newFloatingUnitWithPercent) => newFloatingUnitWithPercent.Validate(), + (newFloatingMatrixWithAllocation) => newFloatingMatrixWithAllocation.Validate(), + (newFloatingTieredWithProration) => newFloatingTieredWithProration.Validate(), + (newFloatingUnitWithProration) => newFloatingUnitWithProration.Validate(), + (newFloatingGroupedAllocation) => newFloatingGroupedAllocation.Validate(), + (newFloatingBulkWithProration) => newFloatingBulkWithProration.Validate(), + (newFloatingGroupedWithProratedMinimum) => + newFloatingGroupedWithProratedMinimum.Validate(), + (newFloatingGroupedWithMeteredMinimum) => + newFloatingGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newFloatingMatrixWithDisplayName) => newFloatingMatrixWithDisplayName.Validate(), + (newFloatingGroupedTieredPackage) => newFloatingGroupedTieredPackage.Validate(), + (newFloatingMaxGroupTieredPackage) => newFloatingMaxGroupTieredPackage.Validate(), + (newFloatingScalableMatrixWithUnitPricing) => + newFloatingScalableMatrixWithUnitPricing.Validate(), + (newFloatingScalableMatrixWithTieredPricing) => + newFloatingScalableMatrixWithTieredPricing.Validate(), + (newFloatingCumulativeGroupedBulk) => newFloatingCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newFloatingMinimumComposite) => newFloatingMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Prices.Price? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceConverter : JsonConverter +{ + public override global::Orb.Models.Prices.Price? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Prices.Price(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Prices.Price? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceBulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required PriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public PriceBulkWithFilters(PriceBulkWithFilters priceBulkWithFilters) + : base(priceBulkWithFilters) { } + + public PriceBulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceBulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceBulkWithFiltersFromRaw : IFromRawJson +{ + /// + public PriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceBulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceBulkWithFiltersBulkWithFiltersConfig, + PriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class PriceBulkWithFiltersBulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public PriceBulkWithFiltersBulkWithFiltersConfig() { } + + public PriceBulkWithFiltersBulkWithFiltersConfig( + PriceBulkWithFiltersBulkWithFiltersConfig priceBulkWithFiltersBulkWithFiltersConfig + ) + : base(priceBulkWithFiltersBulkWithFiltersConfig) { } + + public PriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceBulkWithFiltersBulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public PriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceBulkWithFiltersBulkWithFiltersConfigFilter, + PriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class PriceBulkWithFiltersBulkWithFiltersConfigFilter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public PriceBulkWithFiltersBulkWithFiltersConfigFilter() { } + + public PriceBulkWithFiltersBulkWithFiltersConfigFilter( + PriceBulkWithFiltersBulkWithFiltersConfigFilter priceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base(priceBulkWithFiltersBulkWithFiltersConfigFilter) { } + + public PriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceBulkWithFiltersBulkWithFiltersConfigFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public PriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceBulkWithFiltersBulkWithFiltersConfigTier, + PriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class PriceBulkWithFiltersBulkWithFiltersConfigTier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public PriceBulkWithFiltersBulkWithFiltersConfigTier() { } + + public PriceBulkWithFiltersBulkWithFiltersConfigTier( + PriceBulkWithFiltersBulkWithFiltersConfigTier priceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base(priceBulkWithFiltersBulkWithFiltersConfigTier) { } + + public PriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceBulkWithFiltersBulkWithFiltersConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceBulkWithFiltersBulkWithFiltersConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class PriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public PriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceBulkWithFiltersCadenceConverter))] +public enum PriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceBulkWithFiltersCadenceConverter : JsonConverter +{ + public override PriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceBulkWithFiltersCadence.Annual, + "semi_annual" => PriceBulkWithFiltersCadence.SemiAnnual, + "monthly" => PriceBulkWithFiltersCadence.Monthly, + "quarterly" => PriceBulkWithFiltersCadence.Quarterly, + "one_time" => PriceBulkWithFiltersCadence.OneTime, + "custom" => PriceBulkWithFiltersCadence.Custom, + _ => (PriceBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceBulkWithFiltersCadence.Annual => "annual", + PriceBulkWithFiltersCadence.SemiAnnual => "semi_annual", + PriceBulkWithFiltersCadence.Monthly => "monthly", + PriceBulkWithFiltersCadence.Quarterly => "quarterly", + PriceBulkWithFiltersCadence.OneTime => "one_time", + PriceBulkWithFiltersCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PriceBulkWithFiltersConversionRateConfigConverter))] +public record class PriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceBulkWithFiltersConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator PriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceBulkWithFiltersConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override PriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceBulkWithFiltersConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceGroupedWithMinMaxThresholds, + PriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class PriceGroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public PriceGroupedWithMinMaxThresholds( + PriceGroupedWithMinMaxThresholds priceGroupedWithMinMaxThresholds + ) + : base(priceGroupedWithMinMaxThresholds) { } + + public PriceGroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceGroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceGroupedWithMinMaxThresholdsFromRaw : IFromRawJson +{ + /// + public PriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceGroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceGroupedWithMinMaxThresholdsCadenceConverter))] +public enum PriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override PriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => PriceGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => PriceGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => PriceGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => PriceGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => PriceGroupedWithMinMaxThresholdsCadence.Custom, + _ => (PriceGroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceGroupedWithMinMaxThresholdsCadence.Annual => "annual", + PriceGroupedWithMinMaxThresholdsCadence.SemiAnnual => "semi_annual", + PriceGroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + PriceGroupedWithMinMaxThresholdsCadence.Quarterly => "quarterly", + PriceGroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + PriceGroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() { } + + public PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig priceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base(priceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig) { } + + public PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceGroupedWithMinMaxThresholdsConversionRateConfigConverter))] +public record class PriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceGroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator PriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceGroupedWithMinMaxThresholdsConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override PriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceGroupedWithMinMaxThresholdsConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceCumulativeGroupedAllocation, + PriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class PriceCumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public PriceCumulativeGroupedAllocation( + PriceCumulativeGroupedAllocation priceCumulativeGroupedAllocation + ) + : base(priceCumulativeGroupedAllocation) { } + + public PriceCumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceCumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceCumulativeGroupedAllocationFromRaw : IFromRawJson +{ + /// + public PriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceCumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceCumulativeGroupedAllocationCadenceConverter))] +public enum PriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override PriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => PriceCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => PriceCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => PriceCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => PriceCumulativeGroupedAllocationCadence.OneTime, + "custom" => PriceCumulativeGroupedAllocationCadence.Custom, + _ => (PriceCumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceCumulativeGroupedAllocationCadence.Annual => "annual", + PriceCumulativeGroupedAllocationCadence.SemiAnnual => "semi_annual", + PriceCumulativeGroupedAllocationCadence.Monthly => "monthly", + PriceCumulativeGroupedAllocationCadence.Quarterly => "quarterly", + PriceCumulativeGroupedAllocationCadence.OneTime => "one_time", + PriceCumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() { } + + public PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig priceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base(priceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig) { } + + public PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceCumulativeGroupedAllocationConversionRateConfigConverter))] +public record class PriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceCumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator PriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceCumulativeGroupedAllocationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override PriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceCumulativeGroupedAllocationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required PricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public PricePercent(PricePercent pricePercent) + : base(pricePercent) { } + + public PricePercent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PricePercent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PricePercent FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PricePercentFromRaw : IFromRawJson +{ + /// + public PricePercent FromRawUnchecked(IReadOnlyDictionary rawData) => + PricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PricePercentCadenceConverter))] +public enum PricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PricePercentCadenceConverter : JsonConverter +{ + public override PricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PricePercentCadence.Annual, + "semi_annual" => PricePercentCadence.SemiAnnual, + "monthly" => PricePercentCadence.Monthly, + "quarterly" => PricePercentCadence.Quarterly, + "one_time" => PricePercentCadence.OneTime, + "custom" => PricePercentCadence.Custom, + _ => (PricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PricePercentCadence.Annual => "annual", + PricePercentCadence.SemiAnnual => "semi_annual", + PricePercentCadence.Monthly => "monthly", + PricePercentCadence.Quarterly => "quarterly", + PricePercentCadence.OneTime => "one_time", + PricePercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PricePercentPercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PricePercentPercentConfig() { } + + public PricePercentPercentConfig(PricePercentPercentConfig pricePercentPercentConfig) + : base(pricePercentPercentConfig) { } + + public PricePercentPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PricePercentPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PricePercentPercentConfigFromRaw : IFromRawJson +{ + /// + public PricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PricePercentPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PricePercentConversionRateConfigConverter))] +public record class PricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PricePercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator PricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PricePercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PricePercentConversionRateConfigConverter + : JsonConverter +{ + public override PricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PricePercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceEventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required PriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public PriceEventOutput(PriceEventOutput priceEventOutput) + : base(priceEventOutput) { } + + public PriceEventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEventOutputFromRaw : IFromRawJson +{ + /// + public PriceEventOutput FromRawUnchecked(IReadOnlyDictionary rawData) => + PriceEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceEventOutputCadenceConverter))] +public enum PriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceEventOutputCadenceConverter : JsonConverter +{ + public override PriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceEventOutputCadence.Annual, + "semi_annual" => PriceEventOutputCadence.SemiAnnual, + "monthly" => PriceEventOutputCadence.Monthly, + "quarterly" => PriceEventOutputCadence.Quarterly, + "one_time" => PriceEventOutputCadence.OneTime, + "custom" => PriceEventOutputCadence.Custom, + _ => (PriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceEventOutputCadence.Annual => "annual", + PriceEventOutputCadence.SemiAnnual => "semi_annual", + PriceEventOutputCadence.Monthly => "monthly", + PriceEventOutputCadence.Quarterly => "quarterly", + PriceEventOutputCadence.OneTime => "one_time", + PriceEventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEventOutputEventOutputConfig, + PriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class PriceEventOutputEventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public PriceEventOutputEventOutputConfig() { } + + public PriceEventOutputEventOutputConfig( + PriceEventOutputEventOutputConfig priceEventOutputEventOutputConfig + ) + : base(priceEventOutputEventOutputConfig) { } + + public PriceEventOutputEventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEventOutputEventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceEventOutputEventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class PriceEventOutputEventOutputConfigFromRaw : IFromRawJson +{ + /// + public PriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEventOutputEventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceEventOutputConversionRateConfigConverter))] +public record class PriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator PriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceEventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override PriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluation.cs b/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluation.cs deleted file mode 100644 index bcf186df..00000000 --- a/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluation.cs +++ /dev/null @@ -1,122 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PriceEvaluationProperties = Orb.Models.Prices.PriceEvaluateMultipleParamsProperties.PriceEvaluationProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceEvaluateMultipleParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceEvaluation : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The external ID of a price to evaluate that exists in your Orb account. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// A boolean [computed property](/extensibility/advanced-metrics#computed-properties) - /// used to filter the underlying billable metric - /// - public string? Filter - { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Properties (or [computed properties](/extensibility/advanced-metrics#computed-properties)) - /// used to group the underlying billable metric - /// - public Generic::List? GroupingKeys - { - get - { - if (!this.Properties.TryGetValue("grouping_keys", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["grouping_keys"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An inline price definition to evaluate, allowing you to test price configurations - /// before adding them to Orb. - /// - public PriceEvaluationProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of a price to evaluate that exists in your Orb account. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ExternalPriceID; - _ = this.Filter; - foreach (var item in this.GroupingKeys ?? []) - { - _ = item; - } - this.Price?.Validate(); - _ = this.PriceID; - } - - public PriceEvaluation() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceEvaluation(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PriceEvaluation FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluationProperties/Price.cs b/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluationProperties/Price.cs deleted file mode 100644 index eeee512e..00000000 --- a/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluationProperties/Price.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Prices.PriceEvaluateMultipleParamsProperties.PriceEvaluationProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceEvaluateMultipleParamsProperties.PriceEvaluationProperties; - -/// -/// An inline price definition to evaluate, allowing you to test price configurations -/// before adding them to Orb. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewFloatingUnitPrice Create(Models::NewFloatingUnitPrice value) => - new(value); - - public static PriceVariants::NewFloatingPackagePrice Create( - Models::NewFloatingPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixPrice Create( - Models::NewFloatingMatrixPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixWithAllocationPrice Create( - Models::NewFloatingMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPrice Create( - Models::NewFloatingTieredPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredBPSPrice Create( - Models::NewFloatingTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewFloatingBPSPrice Create(Models::NewFloatingBPSPrice value) => - new(value); - - public static PriceVariants::NewFloatingBulkBPSPrice Create( - Models::NewFloatingBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewFloatingBulkPrice Create(Models::NewFloatingBulkPrice value) => - new(value); - - public static PriceVariants::NewFloatingThresholdTotalAmountPrice Create( - Models::NewFloatingThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPackagePrice Create( - Models::NewFloatingTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedTieredPrice Create( - Models::NewFloatingGroupedTieredPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMaxGroupTieredPackagePrice Create( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredWithMinimumPrice Create( - Models::NewFloatingTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingPackageWithAllocationPrice Create( - Models::NewFloatingPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPackageWithMinimumPrice Create( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingUnitWithPercentPrice Create( - Models::NewFloatingUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredWithProrationPrice Create( - Models::NewFloatingTieredWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingUnitWithProrationPrice Create( - Models::NewFloatingUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedAllocationPrice Create( - Models::NewFloatingGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedWithProratedMinimumPrice Create( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedWithMeteredMinimumPrice Create( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixWithDisplayNamePrice Create( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewFloatingBulkWithProrationPrice Create( - Models::NewFloatingBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedTieredPackagePrice Create( - Models::NewFloatingGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingScalableMatrixWithUnitPricingPrice Create( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewFloatingScalableMatrixWithTieredPricingPrice Create( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewFloatingCumulativeGroupedBulkPrice Create( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluationProperties/PriceVariants/All.cs b/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluationProperties/PriceVariants/All.cs deleted file mode 100644 index 1c64f5c1..00000000 --- a/src/Orb/Models/Prices/PriceEvaluateMultipleParamsProperties/PriceEvaluationProperties/PriceVariants/All.cs +++ /dev/null @@ -1,685 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceEvaluationProperties = Orb.Models.Prices.PriceEvaluateMultipleParamsProperties.PriceEvaluationProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceEvaluateMultipleParamsProperties.PriceEvaluationProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingUnitPrice(Models::NewFloatingUnitPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitPrice From(Models::NewFloatingUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingPackagePrice(Models::NewFloatingPackagePrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingPackagePrice From(Models::NewFloatingPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingMatrixPrice(Models::NewFloatingMatrixPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingMatrixPrice From(Models::NewFloatingMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - >) -)] -public sealed record class NewFloatingMatrixWithAllocationPrice( - Models::NewFloatingMatrixWithAllocationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - > -{ - public static NewFloatingMatrixWithAllocationPrice From( - Models::NewFloatingMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredPrice(Models::NewFloatingTieredPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredPrice From(Models::NewFloatingTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredBPSPrice(Models::NewFloatingTieredBPSPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredBPSPrice From(Models::NewFloatingTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBPSPrice(Models::NewFloatingBPSPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBPSPrice From(Models::NewFloatingBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkBPSPrice(Models::NewFloatingBulkBPSPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkBPSPrice From(Models::NewFloatingBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkPrice(Models::NewFloatingBulkPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkPrice From(Models::NewFloatingBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - >) -)] -public sealed record class NewFloatingThresholdTotalAmountPrice( - Models::NewFloatingThresholdTotalAmountPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - > -{ - public static NewFloatingThresholdTotalAmountPrice From( - Models::NewFloatingThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackagePrice, - Models::NewFloatingTieredPackagePrice - >) -)] -public sealed record class NewFloatingTieredPackagePrice( - Models::NewFloatingTieredPackagePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredPackagePrice From(Models::NewFloatingTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPrice, - Models::NewFloatingGroupedTieredPrice - >) -)] -public sealed record class NewFloatingGroupedTieredPrice( - Models::NewFloatingGroupedTieredPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingGroupedTieredPrice From(Models::NewFloatingGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewFloatingMaxGroupTieredPackagePrice( - Models::NewFloatingMaxGroupTieredPackagePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - > -{ - public static NewFloatingMaxGroupTieredPackagePrice From( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithMinimumPrice, - Models::NewFloatingTieredWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredWithMinimumPrice( - Models::NewFloatingTieredWithMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredWithMinimumPrice From( - Models::NewFloatingTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - >) -)] -public sealed record class NewFloatingPackageWithAllocationPrice( - Models::NewFloatingPackageWithAllocationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - > -{ - public static NewFloatingPackageWithAllocationPrice From( - Models::NewFloatingPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredPackageWithMinimumPrice( - Models::NewFloatingTieredPackageWithMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - > -{ - public static NewFloatingTieredPackageWithMinimumPrice From( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithPercentPrice, - Models::NewFloatingUnitWithPercentPrice - >) -)] -public sealed record class NewFloatingUnitWithPercentPrice( - Models::NewFloatingUnitWithPercentPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitWithPercentPrice From( - Models::NewFloatingUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - >) -)] -public sealed record class NewFloatingTieredWithProrationPrice( - Models::NewFloatingTieredWithProrationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - > -{ - public static NewFloatingTieredWithProrationPrice From( - Models::NewFloatingTieredWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithProrationPrice, - Models::NewFloatingUnitWithProrationPrice - >) -)] -public sealed record class NewFloatingUnitWithProrationPrice( - Models::NewFloatingUnitWithProrationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitWithProrationPrice From( - Models::NewFloatingUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedAllocationPrice, - Models::NewFloatingGroupedAllocationPrice - >) -)] -public sealed record class NewFloatingGroupedAllocationPrice( - Models::NewFloatingGroupedAllocationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingGroupedAllocationPrice From( - Models::NewFloatingGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithProratedMinimumPrice( - Models::NewFloatingGroupedWithProratedMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - > -{ - public static NewFloatingGroupedWithProratedMinimumPrice From( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithMeteredMinimumPrice( - Models::NewFloatingGroupedWithMeteredMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - > -{ - public static NewFloatingGroupedWithMeteredMinimumPrice From( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewFloatingMatrixWithDisplayNamePrice( - Models::NewFloatingMatrixWithDisplayNamePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - > -{ - public static NewFloatingMatrixWithDisplayNamePrice From( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingBulkWithProrationPrice, - Models::NewFloatingBulkWithProrationPrice - >) -)] -public sealed record class NewFloatingBulkWithProrationPrice( - Models::NewFloatingBulkWithProrationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkWithProrationPrice From( - Models::NewFloatingBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - >) -)] -public sealed record class NewFloatingGroupedTieredPackagePrice( - Models::NewFloatingGroupedTieredPackagePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - > -{ - public static NewFloatingGroupedTieredPackagePrice From( - Models::NewFloatingGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice( - Models::NewFloatingScalableMatrixWithUnitPricingPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - > -{ - public static NewFloatingScalableMatrixWithUnitPricingPrice From( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice( - Models::NewFloatingScalableMatrixWithTieredPricingPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - > -{ - public static NewFloatingScalableMatrixWithTieredPricingPrice From( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewFloatingCumulativeGroupedBulkPrice( - Models::NewFloatingCumulativeGroupedBulkPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - > -{ - public static NewFloatingCumulativeGroupedBulkPrice From( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluateMultipleResponse.cs b/src/Orb/Models/Prices/PriceEvaluateMultipleResponse.cs index 282ee794..4770a117 100644 --- a/src/Orb/Models/Prices/PriceEvaluateMultipleResponse.cs +++ b/src/Orb/Models/Prices/PriceEvaluateMultipleResponse.cs @@ -1,32 +1,24 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PriceEvaluateMultipleResponseProperties = Orb.Models.Prices.PriceEvaluateMultipleResponseProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Prices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceEvaluateMultipleResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PriceEvaluateMultipleResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -37,18 +29,143 @@ public override void Validate() public PriceEvaluateMultipleResponse() { } + public PriceEvaluateMultipleResponse( + PriceEvaluateMultipleResponse priceEvaluateMultipleResponse + ) + : base(priceEvaluateMultipleResponse) { } + + public PriceEvaluateMultipleResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceEvaluateMultipleResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + PriceEvaluateMultipleResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PriceEvaluateMultipleResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceEvaluateMultipleResponse(List data) + : this() + { + this.Data = data; + } +} + +class PriceEvaluateMultipleResponseFromRaw : IFromRawJson +{ + /// + public PriceEvaluateMultipleResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluateMultipleResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Data : JsonModel +{ + /// + /// The currency of the price + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The computed price groups associated with input price. + /// + public required IReadOnlyList PriceGroups + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_groups" + ); + } + init { JsonModel.Set(this._rawData, "price_groups", value); } + } + + /// + /// The external ID of the price + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } + + /// + /// The index of the inline price + /// + public long? InlinePriceIndex + { + get { return JsonModel.GetNullableStruct(this.RawData, "inline_price_index"); } + init { JsonModel.Set(this._rawData, "inline_price_index", value); } + } + + /// + /// The ID of the price + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.Currency; + foreach (var item in this.PriceGroups) + { + item.Validate(); + } + _ = this.ExternalPriceID; + _ = this.InlinePriceIndex; + _ = this.PriceID; + } + + public Data() { } + + public Data(Data data) + : base(data) { } + + public Data(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Data(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Data FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DataFromRaw : IFromRawJson +{ + /// + public Data FromRawUnchecked(IReadOnlyDictionary rawData) => + Data.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Prices/PriceEvaluateMultipleResponseProperties/Data.cs b/src/Orb/Models/Prices/PriceEvaluateMultipleResponseProperties/Data.cs deleted file mode 100644 index 747ad316..00000000 --- a/src/Orb/Models/Prices/PriceEvaluateMultipleResponseProperties/Data.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Prices = Orb.Models.Prices; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Prices.PriceEvaluateMultipleResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The currency of the price - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The computed price groups associated with input price. - /// - public required Generic::List PriceGroups - { - get - { - if (!this.Properties.TryGetValue("price_groups", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_groups", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("price_groups"); - } - set { this.Properties["price_groups"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external ID of the price - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The index of the inline price - /// - public long? InlinePriceIndex - { - get - { - if (!this.Properties.TryGetValue("inline_price_index", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["inline_price_index"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The ID of the price - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Currency; - foreach (var item in this.PriceGroups) - { - item.Validate(); - } - _ = this.ExternalPriceID; - _ = this.InlinePriceIndex; - _ = this.PriceID; - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluateParams.cs b/src/Orb/Models/Prices/PriceEvaluateParams.cs index 5db7ad9d..9a558f35 100644 --- a/src/Orb/Models/Prices/PriceEvaluateParams.cs +++ b/src/Orb/Models/Prices/PriceEvaluateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Prices; @@ -12,72 +14,58 @@ namespace Orb.Models.Prices; /// functionality, such as multiple prices, inline price definitions, and querying /// over preview events. /// -/// This endpoint is used to evaluate the output of a price for a given customer -/// and time range. It enables filtering and grouping the output using [computed -/// properties](/extensibility/advanced-metrics#computed-properties), supporting -/// the following workflows: +/// This endpoint is used to evaluate the output of a price for a given customer +/// and time range. It enables filtering and grouping the output using [computed properties](/extensibility/advanced-metrics#computed-properties), +/// supporting the following workflows: /// -/// 1. Showing detailed usage and costs to the end customer. 2. Auditing subtotals -/// on invoice line items. +/// 1. Showing detailed usage and costs to the end customer. 2. Auditing subtotals +/// on invoice line items. /// -/// For these workflows, the expressiveness of computed properties in both the filters -/// and grouping is critical. For example, if you'd like to show your customer their -/// usage grouped by hour and another property, you can do so with the following `grouping_keys`: -/// `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. If you'd -/// like to examine a customer's usage for a specific property value, you can do -/// so with the following `filter`: `my_property = 'foo' AND my_other_property = 'bar'`. +/// For these workflows, the expressiveness of computed properties in both +/// the filters and grouping is critical. For example, if you'd like to show your +/// customer their usage grouped by hour and another property, you can do so with +/// the following `grouping_keys`: `["hour_floor_timestamp_millis(timestamp_millis)", +/// "my_property"]`. If you'd like to examine a customer's usage for a specific property +/// value, you can do so with the following `filter`: `my_property = 'foo' AND my_other_property +/// = 'bar'`. /// -/// By default, the start of the time range must be no more than 100 days ago and -/// the length of the results must be no greater than 1000. Note that this is a POST -/// endpoint rather than a GET endpoint because it employs a JSON body rather than -/// query parameters. +/// By default, the start of the time range must be no more than 100 days ago +/// and the length of the results must be no greater than 1000. Note that this is +/// a POST endpoint rather than a GET endpoint because it employs a JSON body rather +/// than query parameters. /// -public sealed record class PriceEvaluateParams : Orb::ParamsBase +public sealed record class PriceEvaluateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string PriceID; + public string? PriceID { get; init; } /// /// The exclusive upper bound for event timestamps /// - public required System::DateTime TimeframeEnd + public required DateTimeOffset TimeframeEnd { get { - if (!this.BodyProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct(this.RawBodyData, "timeframe_end"); } + init { JsonModel.Set(this._rawBodyData, "timeframe_end", value); } } /// /// The inclusive lower bound for event timestamps /// - public required System::DateTime TimeframeStart + public required DateTimeOffset TimeframeStart { get { - if (!this.BodyProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullStruct(this.RawBodyData, "timeframe_start"); } + init { JsonModel.Set(this._rawBodyData, "timeframe_start", value); } } /// @@ -85,14 +73,8 @@ public sealed record class PriceEvaluateParams : Orb::ParamsBase /// public string? CustomerID { - get - { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } } /// @@ -100,24 +82,8 @@ public string? CustomerID /// public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } /// @@ -126,61 +92,101 @@ public string? ExternalCustomerID /// public string? Filter { - get - { - if (!this.BodyProperties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["filter"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "filter"); } + init { JsonModel.Set(this._rawBodyData, "filter", value); } } /// /// Properties (or [computed properties](/extensibility/advanced-metrics#computed-properties)) /// used to group the underlying billable metric /// - public Generic::List? GroupingKeys + public IReadOnlyList? GroupingKeys { - get + get { return JsonModel.GetNullableClass>(this.RawBodyData, "grouping_keys"); } + init { - if (!this.BodyProperties.TryGetValue("grouping_keys", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.BodyProperties["grouping_keys"] = Json::JsonSerializer.SerializeToElement(value); + JsonModel.Set(this._rawBodyData, "grouping_keys", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public PriceEvaluateParams() { } + + public PriceEvaluateParams(PriceEvaluateParams priceEvaluateParams) + : base(priceEvaluateParams) + { + this._rawBodyData = [.. priceEvaluateParams._rawBodyData]; + } + + public PriceEvaluateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/{0}/evaluate", this.PriceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParams.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParams.cs index b994f0ba..49479e62 100644 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParams.cs +++ b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using PriceEvaluatePreviewEventsParamsProperties = Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Prices; @@ -14,169 +17,7108 @@ namespace Orb.Models.Prices; /// and group results using [computed properties](/extensibility/advanced-metrics#computed-properties) /// to analyze pricing across different dimensions. /// -/// Prices may either reference existing prices in your Orb account or be defined +/// Prices may either reference existing prices in your Orb account or be defined /// inline in the request body. The endpoint has the following limitations: 1. Up /// to 100 prices can be evaluated in a single request. 2. Up to 500 preview events -/// can be provided in a single request. +/// can be provided in a single request. /// -/// A top-level customer_id is required to evaluate the preview events. Additionally, -/// all events without a customer_id will have the top-level customer_id added. +/// A top-level customer_id is required to evaluate the preview events. Additionally, +/// all events without a customer_id will have the top-level customer_id added. /// -/// Note that this is a POST endpoint rather than a GET endpoint because it employs -/// a JSON body rather than query parameters. +/// Note that this is a POST endpoint rather than a GET endpoint because it +/// employs a JSON body rather than query parameters. /// -public sealed record class PriceEvaluatePreviewEventsParams : Orb::ParamsBase +public sealed record class PriceEvaluatePreviewEventsParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// The exclusive upper bound for event timestamps /// - public required System::DateTime TimeframeEnd + public required System::DateTimeOffset TimeframeEnd { get { - if (!this.BodyProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); + return JsonModel.GetNotNullStruct( + this.RawBodyData, + "timeframe_end" + ); + } + init { JsonModel.Set(this._rawBodyData, "timeframe_end", value); } + } - return Json::JsonSerializer.Deserialize(element); + /// + /// The inclusive lower bound for event timestamps + /// + public required System::DateTimeOffset TimeframeStart + { + get + { + return JsonModel.GetNotNullStruct( + this.RawBodyData, + "timeframe_start" + ); } - set + init { JsonModel.Set(this._rawBodyData, "timeframe_start", value); } + } + + /// + /// The ID of the customer to which this evaluation is scoped. + /// + public string? CustomerID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } + } + + /// + /// List of preview events to use instead of actual usage data + /// + public IReadOnlyList? Events + { + get { return JsonModel.GetNullableClass>(this.RawBodyData, "events"); } + init { - this.BodyProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "events", value); } } /// - /// The inclusive lower bound for event timestamps + /// The external customer ID of the customer to which this evaluation is scoped. + /// + public string? ExternalCustomerID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } + } + + /// + /// List of prices to evaluate (max 100) /// - public required System::DateTime TimeframeStart + public IReadOnlyList? PriceEvaluations { get { - if (!this.BodyProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "price_evaluations"); + } + init + { + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawBodyData, "price_evaluations", value); } - set + } + + public PriceEvaluatePreviewEventsParams() { } + + public PriceEvaluatePreviewEventsParams( + PriceEvaluatePreviewEventsParams priceEvaluatePreviewEventsParams + ) + : base(priceEvaluatePreviewEventsParams) + { + this._rawBodyData = [.. priceEvaluatePreviewEventsParams._rawBodyData]; + } + + public PriceEvaluatePreviewEventsParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + "/prices/evaluate_preview_events" + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } + + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - this.BodyProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } +} +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Event : JsonModel +{ /// - /// The ID of the customer to which this evaluation is scoped. + /// A name to meaningfully identify the action or event type. /// - public string? CustomerID + public required string EventName + { + get { return JsonModel.GetNotNullClass(this.RawData, "event_name"); } + init { JsonModel.Set(this._rawData, "event_name", value); } + } + + /// + /// A dictionary of custom properties. Values in this dictionary must be numeric, + /// boolean, or strings. Nested dictionaries are disallowed. + /// + public required IReadOnlyDictionary Properties { get { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullClass>( + this.RawData, + "properties" + ); } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "properties", value); } } /// - /// List of preview events to use instead of actual usage data + /// An ISO 8601 format date with no timezone offset (i.e. UTC). This should represent + /// the time that usage was recorded, and is particularly important to attribute + /// usage to a given billing period. /// - public Generic::List? Events + public required System::DateTimeOffset Timestamp { get { - if (!this.BodyProperties.TryGetValue("events", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); + return JsonModel.GetNotNullStruct(this.RawData, "timestamp"); } - set { this.BodyProperties["events"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "timestamp", value); } } /// - /// The external customer ID of the customer to which this evaluation is scoped. + /// The Orb Customer identifier + /// + public string? CustomerID + { + get { return JsonModel.GetNullableClass(this.RawData, "customer_id"); } + init { JsonModel.Set(this._rawData, "customer_id", value); } + } + + /// + /// An alias for the Orb customer, whose mapping is specified when creating the customer /// public string? ExternalCustomerID { - get + get { return JsonModel.GetNullableClass(this.RawData, "external_customer_id"); } + init { JsonModel.Set(this._rawData, "external_customer_id", value); } + } + + /// + public override void Validate() + { + _ = this.EventName; + _ = this.Properties; + _ = this.Timestamp; + _ = this.CustomerID; + _ = this.ExternalCustomerID; + } + + public Event() { } + + public Event(Event event1) + : base(event1) { } + + public Event(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Event(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Event FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventFromRaw : IFromRawJson +{ + /// + public Event FromRawUnchecked(IReadOnlyDictionary rawData) => + Event.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluation, + PriceEvaluatePreviewEventsParamsPriceEvaluationFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluation : JsonModel +{ + /// + /// The external ID of a price to evaluate that exists in your Orb account. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// A boolean [computed property](/extensibility/advanced-metrics#computed-properties) + /// used to filter the underlying billable metric + /// + public string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// Properties (or [computed properties](/extensibility/advanced-metrics#computed-properties)) + /// used to group the underlying billable metric + /// + public IReadOnlyList? GroupingKeys + { + get { return JsonModel.GetNullableClass>(this.RawData, "grouping_keys"); } + init { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawData, "grouping_keys", value); } - set + } + + /// + /// New floating price request body params. + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice? Price + { + get { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "price" ); } + init { JsonModel.Set(this._rawData, "price", value); } } /// - /// List of prices to evaluate (max 100) + /// The ID of a price to evaluate that exists in your Orb account. /// - public Generic::List? PriceEvaluations + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.ExternalPriceID; + _ = this.Filter; + _ = this.GroupingKeys; + this.Price?.Validate(); + _ = this.PriceID; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluation() { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluation( + PriceEvaluatePreviewEventsParamsPriceEvaluation priceEvaluatePreviewEventsParamsPriceEvaluation + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluation) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluatePreviewEventsParamsPriceEvaluation.FromRawUnchecked(rawData); +} + +/// +/// New floating price request body params. +/// +[JsonConverter(typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceConverter))] +public record class PriceEvaluatePreviewEventsParamsPriceEvaluationPrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Currency { get { - if ( - !this.BodyProperties.TryGetValue("price_evaluations", out Json::JsonElement element) - ) - return null; + return Match( + newFloatingUnit: (x) => x.Currency, + newFloatingTiered: (x) => x.Currency, + newFloatingBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newFloatingPackage: (x) => x.Currency, + newFloatingMatrix: (x) => x.Currency, + newFloatingThresholdTotalAmount: (x) => x.Currency, + newFloatingTieredPackage: (x) => x.Currency, + newFloatingTieredWithMinimum: (x) => x.Currency, + newFloatingGroupedTiered: (x) => x.Currency, + newFloatingTieredPackageWithMinimum: (x) => x.Currency, + newFloatingPackageWithAllocation: (x) => x.Currency, + newFloatingUnitWithPercent: (x) => x.Currency, + newFloatingMatrixWithAllocation: (x) => x.Currency, + newFloatingTieredWithProration: (x) => x.Currency, + newFloatingUnitWithProration: (x) => x.Currency, + newFloatingGroupedAllocation: (x) => x.Currency, + newFloatingBulkWithProration: (x) => x.Currency, + newFloatingGroupedWithProratedMinimum: (x) => x.Currency, + newFloatingGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newFloatingMatrixWithDisplayName: (x) => x.Currency, + newFloatingGroupedTieredPackage: (x) => x.Currency, + newFloatingMaxGroupTieredPackage: (x) => x.Currency, + newFloatingScalableMatrixWithUnitPricing: (x) => x.Currency, + newFloatingScalableMatrixWithTieredPricing: (x) => x.Currency, + newFloatingCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newFloatingMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } - return Json::JsonSerializer.Deserialize?>( - element + public string ItemID + { + get + { + return Match( + newFloatingUnit: (x) => x.ItemID, + newFloatingTiered: (x) => x.ItemID, + newFloatingBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newFloatingPackage: (x) => x.ItemID, + newFloatingMatrix: (x) => x.ItemID, + newFloatingThresholdTotalAmount: (x) => x.ItemID, + newFloatingTieredPackage: (x) => x.ItemID, + newFloatingTieredWithMinimum: (x) => x.ItemID, + newFloatingGroupedTiered: (x) => x.ItemID, + newFloatingTieredPackageWithMinimum: (x) => x.ItemID, + newFloatingPackageWithAllocation: (x) => x.ItemID, + newFloatingUnitWithPercent: (x) => x.ItemID, + newFloatingMatrixWithAllocation: (x) => x.ItemID, + newFloatingTieredWithProration: (x) => x.ItemID, + newFloatingUnitWithProration: (x) => x.ItemID, + newFloatingGroupedAllocation: (x) => x.ItemID, + newFloatingBulkWithProration: (x) => x.ItemID, + newFloatingGroupedWithProratedMinimum: (x) => x.ItemID, + newFloatingGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newFloatingMatrixWithDisplayName: (x) => x.ItemID, + newFloatingGroupedTieredPackage: (x) => x.ItemID, + newFloatingMaxGroupTieredPackage: (x) => x.ItemID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ItemID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ItemID, + newFloatingCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newFloatingMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID ); } - set + } + + public string Name + { + get { - this.BodyProperties["price_evaluations"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newFloatingUnit: (x) => x.Name, + newFloatingTiered: (x) => x.Name, + newFloatingBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newFloatingPackage: (x) => x.Name, + newFloatingMatrix: (x) => x.Name, + newFloatingThresholdTotalAmount: (x) => x.Name, + newFloatingTieredPackage: (x) => x.Name, + newFloatingTieredWithMinimum: (x) => x.Name, + newFloatingGroupedTiered: (x) => x.Name, + newFloatingTieredPackageWithMinimum: (x) => x.Name, + newFloatingPackageWithAllocation: (x) => x.Name, + newFloatingUnitWithPercent: (x) => x.Name, + newFloatingMatrixWithAllocation: (x) => x.Name, + newFloatingTieredWithProration: (x) => x.Name, + newFloatingUnitWithProration: (x) => x.Name, + newFloatingGroupedAllocation: (x) => x.Name, + newFloatingBulkWithProration: (x) => x.Name, + newFloatingGroupedWithProratedMinimum: (x) => x.Name, + newFloatingGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newFloatingMatrixWithDisplayName: (x) => x.Name, + newFloatingGroupedTieredPackage: (x) => x.Name, + newFloatingMaxGroupTieredPackage: (x) => x.Name, + newFloatingScalableMatrixWithUnitPricing: (x) => x.Name, + newFloatingScalableMatrixWithTieredPricing: (x) => x.Name, + newFloatingCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newFloatingMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name ); } } - public override System::Uri Url(Orb::IOrbClient client) + public string? BillableMetricID { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + "/prices/evaluate_preview_events" - ) + get { - Query = this.QueryString(client), - }.Uri; + return Match( + newFloatingUnit: (x) => x.BillableMetricID, + newFloatingTiered: (x) => x.BillableMetricID, + newFloatingBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newFloatingPackage: (x) => x.BillableMetricID, + newFloatingMatrix: (x) => x.BillableMetricID, + newFloatingThresholdTotalAmount: (x) => x.BillableMetricID, + newFloatingTieredPackage: (x) => x.BillableMetricID, + newFloatingTieredWithMinimum: (x) => x.BillableMetricID, + newFloatingGroupedTiered: (x) => x.BillableMetricID, + newFloatingTieredPackageWithMinimum: (x) => x.BillableMetricID, + newFloatingPackageWithAllocation: (x) => x.BillableMetricID, + newFloatingUnitWithPercent: (x) => x.BillableMetricID, + newFloatingMatrixWithAllocation: (x) => x.BillableMetricID, + newFloatingTieredWithProration: (x) => x.BillableMetricID, + newFloatingUnitWithProration: (x) => x.BillableMetricID, + newFloatingGroupedAllocation: (x) => x.BillableMetricID, + newFloatingBulkWithProration: (x) => x.BillableMetricID, + newFloatingGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newFloatingGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newFloatingMatrixWithDisplayName: (x) => x.BillableMetricID, + newFloatingGroupedTieredPackage: (x) => x.BillableMetricID, + newFloatingMaxGroupTieredPackage: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newFloatingCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newFloatingMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } } - public Http::StringContent BodyContent() + public bool? BilledInAdvance { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + get + { + return Match( + newFloatingUnit: (x) => x.BilledInAdvance, + newFloatingTiered: (x) => x.BilledInAdvance, + newFloatingBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newFloatingPackage: (x) => x.BilledInAdvance, + newFloatingMatrix: (x) => x.BilledInAdvance, + newFloatingThresholdTotalAmount: (x) => x.BilledInAdvance, + newFloatingTieredPackage: (x) => x.BilledInAdvance, + newFloatingTieredWithMinimum: (x) => x.BilledInAdvance, + newFloatingGroupedTiered: (x) => x.BilledInAdvance, + newFloatingTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newFloatingPackageWithAllocation: (x) => x.BilledInAdvance, + newFloatingUnitWithPercent: (x) => x.BilledInAdvance, + newFloatingMatrixWithAllocation: (x) => x.BilledInAdvance, + newFloatingTieredWithProration: (x) => x.BilledInAdvance, + newFloatingUnitWithProration: (x) => x.BilledInAdvance, + newFloatingGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingBulkWithProration: (x) => x.BilledInAdvance, + newFloatingGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newFloatingGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newFloatingMatrixWithDisplayName: (x) => x.BilledInAdvance, + newFloatingGroupedTieredPackage: (x) => x.BilledInAdvance, + newFloatingMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newFloatingCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.BillingCycleConfiguration, + newFloatingTiered: (x) => x.BillingCycleConfiguration, + newFloatingBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newFloatingPackage: (x) => x.BillingCycleConfiguration, + newFloatingMatrix: (x) => x.BillingCycleConfiguration, + newFloatingThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTiered: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newFloatingPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithPercent: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithProration: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithProration: (x) => x.BillingCycleConfiguration, + newFloatingGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingBulkWithProration: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newFloatingUnit: (x) => x.ConversionRate, + newFloatingTiered: (x) => x.ConversionRate, + newFloatingBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newFloatingPackage: (x) => x.ConversionRate, + newFloatingMatrix: (x) => x.ConversionRate, + newFloatingThresholdTotalAmount: (x) => x.ConversionRate, + newFloatingTieredPackage: (x) => x.ConversionRate, + newFloatingTieredWithMinimum: (x) => x.ConversionRate, + newFloatingGroupedTiered: (x) => x.ConversionRate, + newFloatingTieredPackageWithMinimum: (x) => x.ConversionRate, + newFloatingPackageWithAllocation: (x) => x.ConversionRate, + newFloatingUnitWithPercent: (x) => x.ConversionRate, + newFloatingMatrixWithAllocation: (x) => x.ConversionRate, + newFloatingTieredWithProration: (x) => x.ConversionRate, + newFloatingUnitWithProration: (x) => x.ConversionRate, + newFloatingGroupedAllocation: (x) => x.ConversionRate, + newFloatingBulkWithProration: (x) => x.ConversionRate, + newFloatingGroupedWithProratedMinimum: (x) => x.ConversionRate, + newFloatingGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newFloatingMatrixWithDisplayName: (x) => x.ConversionRate, + newFloatingGroupedTieredPackage: (x) => x.ConversionRate, + newFloatingMaxGroupTieredPackage: (x) => x.ConversionRate, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newFloatingCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newFloatingMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.DimensionalPriceConfiguration, + newFloatingTiered: (x) => x.DimensionalPriceConfiguration, + newFloatingBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newFloatingPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrix: (x) => x.DimensionalPriceConfiguration, + newFloatingThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newFloatingUnit: (x) => x.ExternalPriceID, + newFloatingTiered: (x) => x.ExternalPriceID, + newFloatingBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newFloatingPackage: (x) => x.ExternalPriceID, + newFloatingMatrix: (x) => x.ExternalPriceID, + newFloatingThresholdTotalAmount: (x) => x.ExternalPriceID, + newFloatingTieredPackage: (x) => x.ExternalPriceID, + newFloatingTieredWithMinimum: (x) => x.ExternalPriceID, + newFloatingGroupedTiered: (x) => x.ExternalPriceID, + newFloatingTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newFloatingPackageWithAllocation: (x) => x.ExternalPriceID, + newFloatingUnitWithPercent: (x) => x.ExternalPriceID, + newFloatingMatrixWithAllocation: (x) => x.ExternalPriceID, + newFloatingTieredWithProration: (x) => x.ExternalPriceID, + newFloatingUnitWithProration: (x) => x.ExternalPriceID, + newFloatingGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingBulkWithProration: (x) => x.ExternalPriceID, + newFloatingGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newFloatingGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newFloatingMatrixWithDisplayName: (x) => x.ExternalPriceID, + newFloatingGroupedTieredPackage: (x) => x.ExternalPriceID, + newFloatingMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newFloatingCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newFloatingUnit: (x) => x.FixedPriceQuantity, + newFloatingTiered: (x) => x.FixedPriceQuantity, + newFloatingBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newFloatingPackage: (x) => x.FixedPriceQuantity, + newFloatingMatrix: (x) => x.FixedPriceQuantity, + newFloatingThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newFloatingTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingTieredWithMinimum: (x) => x.FixedPriceQuantity, + newFloatingGroupedTiered: (x) => x.FixedPriceQuantity, + newFloatingTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newFloatingPackageWithAllocation: (x) => x.FixedPriceQuantity, + newFloatingUnitWithPercent: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithAllocation: (x) => x.FixedPriceQuantity, + newFloatingTieredWithProration: (x) => x.FixedPriceQuantity, + newFloatingUnitWithProration: (x) => x.FixedPriceQuantity, + newFloatingGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingBulkWithProration: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newFloatingGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newFloatingCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newFloatingUnit: (x) => x.InvoiceGroupingKey, + newFloatingTiered: (x) => x.InvoiceGroupingKey, + newFloatingBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newFloatingPackage: (x) => x.InvoiceGroupingKey, + newFloatingMatrix: (x) => x.InvoiceGroupingKey, + newFloatingThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTiered: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newFloatingPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithPercent: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithProration: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithProration: (x) => x.InvoiceGroupingKey, + newFloatingGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingBulkWithProration: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newFloatingCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + newFloatingUnit: (x) => x.InvoicingCycleConfiguration, + newFloatingTiered: (x) => x.InvoicingCycleConfiguration, + newFloatingBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newFloatingPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrix: (x) => x.InvoicingCycleConfiguration, + newFloatingThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); } } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingUnitPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMatrixPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingThresholdTotalAmountPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedTieredPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredPackageWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingPackageWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingUnitWithPercentPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMatrixWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingUnitWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingBulkWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedWithProratedMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedWithMeteredMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMatrixWithDisplayNamePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMaxGroupTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingCumulativeGroupedBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMinimumCompositePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnit(out var value)) { + /// // `value` is of type `NewFloatingUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnit([NotNullWhen(true)] out NewFloatingUnitPrice? value) + { + value = this.Value as NewFloatingUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTiered(out var value)) { + /// // `value` is of type `NewFloatingTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTiered([NotNullWhen(true)] out NewFloatingTieredPrice? value) + { + value = this.Value as NewFloatingTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulk(out var value)) { + /// // `value` is of type `NewFloatingBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulk([NotNullWhen(true)] out NewFloatingBulkPrice? value) + { + value = this.Value as NewFloatingBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] + out PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters? value + ) + { + value = this.Value as PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackage(out var value)) { + /// // `value` is of type `NewFloatingPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackage([NotNullWhen(true)] out NewFloatingPackagePrice? value) + { + value = this.Value as NewFloatingPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrix(out var value)) { + /// // `value` is of type `NewFloatingMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrix([NotNullWhen(true)] out NewFloatingMatrixPrice? value) + { + value = this.Value as NewFloatingMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewFloatingThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingThresholdTotalAmount( + [NotNullWhen(true)] out NewFloatingThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewFloatingThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackage( + [NotNullWhen(true)] out NewFloatingTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithMinimum(out var value)) { + /// // `value` is of type `NewFloatingTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithMinimum( + [NotNullWhen(true)] out NewFloatingTieredWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTiered(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTiered( + [NotNullWhen(true)] out NewFloatingGroupedTieredPrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewFloatingTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackageWithMinimum( + [NotNullWhen(true)] out NewFloatingTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackageWithAllocation(out var value)) { + /// // `value` is of type `NewFloatingPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackageWithAllocation( + [NotNullWhen(true)] out NewFloatingPackageWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithPercent(out var value)) { + /// // `value` is of type `NewFloatingUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithPercent( + [NotNullWhen(true)] out NewFloatingUnitWithPercentPrice? value + ) + { + value = this.Value as NewFloatingUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithAllocation( + [NotNullWhen(true)] out NewFloatingMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithProration(out var value)) { + /// // `value` is of type `NewFloatingTieredWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithProration( + [NotNullWhen(true)] out NewFloatingTieredWithProrationPrice? value + ) + { + value = this.Value as NewFloatingTieredWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithProration(out var value)) { + /// // `value` is of type `NewFloatingUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithProration( + [NotNullWhen(true)] out NewFloatingUnitWithProrationPrice? value + ) + { + value = this.Value as NewFloatingUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedAllocation(out var value)) { + /// // `value` is of type `NewFloatingGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedAllocation( + [NotNullWhen(true)] out NewFloatingGroupedAllocationPrice? value + ) + { + value = this.Value as NewFloatingGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulkWithProration(out var value)) { + /// // `value` is of type `NewFloatingBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulkWithProration( + [NotNullWhen(true)] out NewFloatingBulkWithProrationPrice? value + ) + { + value = this.Value as NewFloatingBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewFloatingGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewFloatingGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] + out PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds? value + ) + { + value = + this.Value + as PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithDisplayName( + [NotNullWhen(true)] out NewFloatingMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewFloatingMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTieredPackage( + [NotNullWhen(true)] out NewFloatingGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMaxGroupTieredPackage( + [NotNullWhen(true)] out NewFloatingMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewFloatingCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingCumulativeGroupedBulk( + [NotNullWhen(true)] out NewFloatingCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewFloatingCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] + out PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation? value + ) + { + value = + this.Value + as PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMinimumComposite(out var value)) { + /// // `value` is of type `NewFloatingMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMinimumComposite( + [NotNullWhen(true)] out NewFloatingMinimumCompositePrice? value + ) + { + value = this.Value as NewFloatingMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent( + [NotNullWhen(true)] out PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent? value + ) + { + value = this.Value as PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] + out PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput? value + ) + { + value = this.Value as PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newFloatingUnit, + System::Action newFloatingTiered, + System::Action newFloatingBulk, + System::Action bulkWithFilters, + System::Action newFloatingPackage, + System::Action newFloatingMatrix, + System::Action newFloatingThresholdTotalAmount, + System::Action newFloatingTieredPackage, + System::Action newFloatingTieredWithMinimum, + System::Action newFloatingGroupedTiered, + System::Action newFloatingTieredPackageWithMinimum, + System::Action newFloatingPackageWithAllocation, + System::Action newFloatingUnitWithPercent, + System::Action newFloatingMatrixWithAllocation, + System::Action newFloatingTieredWithProration, + System::Action newFloatingUnitWithProration, + System::Action newFloatingGroupedAllocation, + System::Action newFloatingBulkWithProration, + System::Action newFloatingGroupedWithProratedMinimum, + System::Action newFloatingGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newFloatingMatrixWithDisplayName, + System::Action newFloatingGroupedTieredPackage, + System::Action newFloatingMaxGroupTieredPackage, + System::Action newFloatingScalableMatrixWithUnitPricing, + System::Action newFloatingScalableMatrixWithTieredPricing, + System::Action newFloatingCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newFloatingMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewFloatingUnitPrice value: + newFloatingUnit(value); + break; + case NewFloatingTieredPrice value: + newFloatingTiered(value); + break; + case NewFloatingBulkPrice value: + newFloatingBulk(value); + break; + case PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewFloatingPackagePrice value: + newFloatingPackage(value); + break; + case NewFloatingMatrixPrice value: + newFloatingMatrix(value); + break; + case NewFloatingThresholdTotalAmountPrice value: + newFloatingThresholdTotalAmount(value); + break; + case NewFloatingTieredPackagePrice value: + newFloatingTieredPackage(value); + break; + case NewFloatingTieredWithMinimumPrice value: + newFloatingTieredWithMinimum(value); + break; + case NewFloatingGroupedTieredPrice value: + newFloatingGroupedTiered(value); + break; + case NewFloatingTieredPackageWithMinimumPrice value: + newFloatingTieredPackageWithMinimum(value); + break; + case NewFloatingPackageWithAllocationPrice value: + newFloatingPackageWithAllocation(value); + break; + case NewFloatingUnitWithPercentPrice value: + newFloatingUnitWithPercent(value); + break; + case NewFloatingMatrixWithAllocationPrice value: + newFloatingMatrixWithAllocation(value); + break; + case NewFloatingTieredWithProrationPrice value: + newFloatingTieredWithProration(value); + break; + case NewFloatingUnitWithProrationPrice value: + newFloatingUnitWithProration(value); + break; + case NewFloatingGroupedAllocationPrice value: + newFloatingGroupedAllocation(value); + break; + case NewFloatingBulkWithProrationPrice value: + newFloatingBulkWithProration(value); + break; + case NewFloatingGroupedWithProratedMinimumPrice value: + newFloatingGroupedWithProratedMinimum(value); + break; + case NewFloatingGroupedWithMeteredMinimumPrice value: + newFloatingGroupedWithMeteredMinimum(value); + break; + case PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewFloatingMatrixWithDisplayNamePrice value: + newFloatingMatrixWithDisplayName(value); + break; + case NewFloatingGroupedTieredPackagePrice value: + newFloatingGroupedTieredPackage(value); + break; + case NewFloatingMaxGroupTieredPackagePrice value: + newFloatingMaxGroupTieredPackage(value); + break; + case NewFloatingScalableMatrixWithUnitPricingPrice value: + newFloatingScalableMatrixWithUnitPricing(value); + break; + case NewFloatingScalableMatrixWithTieredPricingPrice value: + newFloatingScalableMatrixWithTieredPricing(value); + break; + case NewFloatingCumulativeGroupedBulkPrice value: + newFloatingCumulativeGroupedBulk(value); + break; + case PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewFloatingMinimumCompositePrice value: + newFloatingMinimumComposite(value); + break; + case PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent value: + percent(value); + break; + case PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPrice" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent value) => {...}, + /// (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newFloatingUnit, + System::Func newFloatingTiered, + System::Func newFloatingBulk, + System::Func< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters, + T + > bulkWithFilters, + System::Func newFloatingPackage, + System::Func newFloatingMatrix, + System::Func newFloatingThresholdTotalAmount, + System::Func newFloatingTieredPackage, + System::Func newFloatingTieredWithMinimum, + System::Func newFloatingGroupedTiered, + System::Func< + NewFloatingTieredPackageWithMinimumPrice, + T + > newFloatingTieredPackageWithMinimum, + System::Func newFloatingPackageWithAllocation, + System::Func newFloatingUnitWithPercent, + System::Func newFloatingMatrixWithAllocation, + System::Func newFloatingTieredWithProration, + System::Func newFloatingUnitWithProration, + System::Func newFloatingGroupedAllocation, + System::Func newFloatingBulkWithProration, + System::Func< + NewFloatingGroupedWithProratedMinimumPrice, + T + > newFloatingGroupedWithProratedMinimum, + System::Func< + NewFloatingGroupedWithMeteredMinimumPrice, + T + > newFloatingGroupedWithMeteredMinimum, + System::Func< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func newFloatingMatrixWithDisplayName, + System::Func newFloatingGroupedTieredPackage, + System::Func newFloatingMaxGroupTieredPackage, + System::Func< + NewFloatingScalableMatrixWithUnitPricingPrice, + T + > newFloatingScalableMatrixWithUnitPricing, + System::Func< + NewFloatingScalableMatrixWithTieredPricingPrice, + T + > newFloatingScalableMatrixWithTieredPricing, + System::Func newFloatingCumulativeGroupedBulk, + System::Func< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newFloatingMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewFloatingUnitPrice value => newFloatingUnit(value), + NewFloatingTieredPrice value => newFloatingTiered(value), + NewFloatingBulkPrice value => newFloatingBulk(value), + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters value => + bulkWithFilters(value), + NewFloatingPackagePrice value => newFloatingPackage(value), + NewFloatingMatrixPrice value => newFloatingMatrix(value), + NewFloatingThresholdTotalAmountPrice value => newFloatingThresholdTotalAmount(value), + NewFloatingTieredPackagePrice value => newFloatingTieredPackage(value), + NewFloatingTieredWithMinimumPrice value => newFloatingTieredWithMinimum(value), + NewFloatingGroupedTieredPrice value => newFloatingGroupedTiered(value), + NewFloatingTieredPackageWithMinimumPrice value => newFloatingTieredPackageWithMinimum( + value + ), + NewFloatingPackageWithAllocationPrice value => newFloatingPackageWithAllocation(value), + NewFloatingUnitWithPercentPrice value => newFloatingUnitWithPercent(value), + NewFloatingMatrixWithAllocationPrice value => newFloatingMatrixWithAllocation(value), + NewFloatingTieredWithProrationPrice value => newFloatingTieredWithProration(value), + NewFloatingUnitWithProrationPrice value => newFloatingUnitWithProration(value), + NewFloatingGroupedAllocationPrice value => newFloatingGroupedAllocation(value), + NewFloatingBulkWithProrationPrice value => newFloatingBulkWithProration(value), + NewFloatingGroupedWithProratedMinimumPrice value => + newFloatingGroupedWithProratedMinimum(value), + NewFloatingGroupedWithMeteredMinimumPrice value => newFloatingGroupedWithMeteredMinimum( + value + ), + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewFloatingMatrixWithDisplayNamePrice value => newFloatingMatrixWithDisplayName(value), + NewFloatingGroupedTieredPackagePrice value => newFloatingGroupedTieredPackage(value), + NewFloatingMaxGroupTieredPackagePrice value => newFloatingMaxGroupTieredPackage(value), + NewFloatingScalableMatrixWithUnitPricingPrice value => + newFloatingScalableMatrixWithUnitPricing(value), + NewFloatingScalableMatrixWithTieredPricingPrice value => + newFloatingScalableMatrixWithTieredPricing(value), + NewFloatingCumulativeGroupedBulkPrice value => newFloatingCumulativeGroupedBulk(value), + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewFloatingMinimumCompositePrice value => newFloatingMinimumComposite(value), + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent value => percent(value), + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput value => eventOutput( + value + ), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPrice" + ), + }; + } + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingUnitPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingBulkPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingPackagePrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMatrixPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredPackagePrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedTieredPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingUnitWithPercentPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingTieredWithProrationPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingUnitWithProrationPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedAllocationPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingBulkWithProrationPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + NewFloatingMinimumCompositePrice value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPrice( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPrice" + ); + } + this.Switch( + (newFloatingUnit) => newFloatingUnit.Validate(), + (newFloatingTiered) => newFloatingTiered.Validate(), + (newFloatingBulk) => newFloatingBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newFloatingPackage) => newFloatingPackage.Validate(), + (newFloatingMatrix) => newFloatingMatrix.Validate(), + (newFloatingThresholdTotalAmount) => newFloatingThresholdTotalAmount.Validate(), + (newFloatingTieredPackage) => newFloatingTieredPackage.Validate(), + (newFloatingTieredWithMinimum) => newFloatingTieredWithMinimum.Validate(), + (newFloatingGroupedTiered) => newFloatingGroupedTiered.Validate(), + (newFloatingTieredPackageWithMinimum) => newFloatingTieredPackageWithMinimum.Validate(), + (newFloatingPackageWithAllocation) => newFloatingPackageWithAllocation.Validate(), + (newFloatingUnitWithPercent) => newFloatingUnitWithPercent.Validate(), + (newFloatingMatrixWithAllocation) => newFloatingMatrixWithAllocation.Validate(), + (newFloatingTieredWithProration) => newFloatingTieredWithProration.Validate(), + (newFloatingUnitWithProration) => newFloatingUnitWithProration.Validate(), + (newFloatingGroupedAllocation) => newFloatingGroupedAllocation.Validate(), + (newFloatingBulkWithProration) => newFloatingBulkWithProration.Validate(), + (newFloatingGroupedWithProratedMinimum) => + newFloatingGroupedWithProratedMinimum.Validate(), + (newFloatingGroupedWithMeteredMinimum) => + newFloatingGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newFloatingMatrixWithDisplayName) => newFloatingMatrixWithDisplayName.Validate(), + (newFloatingGroupedTieredPackage) => newFloatingGroupedTieredPackage.Validate(), + (newFloatingMaxGroupTieredPackage) => newFloatingMaxGroupTieredPackage.Validate(), + (newFloatingScalableMatrixWithUnitPricing) => + newFloatingScalableMatrixWithUnitPricing.Validate(), + (newFloatingScalableMatrixWithTieredPricing) => + newFloatingScalableMatrixWithTieredPricing.Validate(), + (newFloatingCumulativeGroupedBulk) => newFloatingCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newFloatingMinimumComposite) => newFloatingMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(PriceEvaluatePreviewEventsParamsPriceEvaluationPrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEvaluatePreviewEventsParamsPriceEvaluationPrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFilters.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig() + { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + ) + : base( + priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig + ) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter() + { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base( + priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter + ) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier() + { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base( + priceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier + ) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier( + string unitAmount + ) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadenceConverter) +)] +public enum PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual, + "semi_annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.SemiAnnual, + "monthly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Monthly, + "quarterly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Quarterly, + "one_time" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.OneTime, + "custom" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Custom, + _ => (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Annual => + "annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.SemiAnnual => + "semi_annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Monthly => + "monthly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Quarterly => + "quarterly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.OneTime => + "one_time", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfigConverter) +)] +public record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds priceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholds.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadenceConverter) +)] +public enum PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Custom, + _ => + (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Annual => + "annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Monthly => + "monthly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Quarterly => + "quarterly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.OneTime => + "one_time", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() + { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig priceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base( + priceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation priceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocation.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadenceConverter) +)] +public enum PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.OneTime, + "custom" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Custom, + _ => + (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Annual => + "annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Monthly => + "monthly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Quarterly => + "quarterly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.OneTime => + "one_time", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() + { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig priceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base( + priceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent priceEvaluatePreviewEventsParamsPriceEvaluationPricePercent + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPricePercent) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadenceConverter))] +public enum PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadenceConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual, + "semi_annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.SemiAnnual, + "monthly" => PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Monthly, + "quarterly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Quarterly, + "one_time" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.OneTime, + "custom" => PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Custom, + _ => (PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Annual => + "annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.SemiAnnual => + "semi_annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Monthly => + "monthly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Quarterly => + "quarterly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.OneTime => + "one_time", + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfigFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig + : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig() { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig priceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfigFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentPercentConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfigConverter) +)] +public record class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfigConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput priceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadenceConverter) +)] +public enum PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadenceConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual, + "semi_annual" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.SemiAnnual, + "monthly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Monthly, + "quarterly" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Quarterly, + "one_time" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.OneTime, + "custom" => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Custom, + _ => (PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Annual => + "annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.SemiAnnual => + "semi_annual", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Monthly => + "monthly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Quarterly => + "quarterly", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.OneTime => + "one_time", + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig() { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig priceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig + ) + : base(priceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig) { } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig( + string unitRatingKey + ) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputEventOutputConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfigConverter) +)] +public record class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceEvaluatePreviewEventsParamsPriceEvaluationPriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/Event.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/Event.cs deleted file mode 100644 index e252fbce..00000000 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/Event.cs +++ /dev/null @@ -1,134 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Event : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// A name to meaningfully identify the action or event type. - /// - public required string EventName - { - get - { - if (!this.Properties.TryGetValue("event_name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "event_name", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("event_name"); - } - set { this.Properties["event_name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A dictionary of custom properties. Values in this dictionary must be numeric, - /// boolean, or strings. Nested dictionaries are disallowed. - /// - public required Generic::Dictionary Properties1 - { - get - { - if (!this.Properties.TryGetValue("properties", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "properties", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("properties"); - } - set { this.Properties["properties"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An ISO 8601 format date with no timezone offset (i.e. UTC). This should represent - /// the time that usage was recorded, and is particularly important to attribute - /// usage to a given billing period. - /// - public required System::DateTime Timestamp - { - get - { - if (!this.Properties.TryGetValue("timestamp", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timestamp", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timestamp"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The Orb Customer identifier - /// - public string? CustomerID - { - get - { - if (!this.Properties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An alias for the Orb customer, whose mapping is specified when creating the customer - /// - public string? ExternalCustomerID - { - get - { - if (!this.Properties.TryGetValue("external_customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - _ = this.EventName; - foreach (var item in this.Properties1.Values) - { - _ = item; - } - _ = this.Timestamp; - _ = this.CustomerID; - _ = this.ExternalCustomerID; - } - - public Event() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Event(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Event FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluation.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluation.cs deleted file mode 100644 index 13b8e6e0..00000000 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluation.cs +++ /dev/null @@ -1,122 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PriceEvaluationProperties = Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties.PriceEvaluationProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceEvaluation : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The external ID of a price to evaluate that exists in your Orb account. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// A boolean [computed property](/extensibility/advanced-metrics#computed-properties) - /// used to filter the underlying billable metric - /// - public string? Filter - { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Properties (or [computed properties](/extensibility/advanced-metrics#computed-properties)) - /// used to group the underlying billable metric - /// - public Generic::List? GroupingKeys - { - get - { - if (!this.Properties.TryGetValue("grouping_keys", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["grouping_keys"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An inline price definition to evaluate, allowing you to test price configurations - /// before adding them to Orb. - /// - public PriceEvaluationProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The ID of a price to evaluate that exists in your Orb account. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ExternalPriceID; - _ = this.Filter; - foreach (var item in this.GroupingKeys ?? []) - { - _ = item; - } - this.Price?.Validate(); - _ = this.PriceID; - } - - public PriceEvaluation() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceEvaluation(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static PriceEvaluation FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluationProperties/Price.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluationProperties/Price.cs deleted file mode 100644 index 9d86d2c4..00000000 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluationProperties/Price.cs +++ /dev/null @@ -1,127 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties.PriceEvaluationProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties.PriceEvaluationProperties; - -/// -/// An inline price definition to evaluate, allowing you to test price configurations -/// before adding them to Orb. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewFloatingUnitPrice Create(Models::NewFloatingUnitPrice value) => - new(value); - - public static PriceVariants::NewFloatingPackagePrice Create( - Models::NewFloatingPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixPrice Create( - Models::NewFloatingMatrixPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixWithAllocationPrice Create( - Models::NewFloatingMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPrice Create( - Models::NewFloatingTieredPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredBPSPrice Create( - Models::NewFloatingTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewFloatingBPSPrice Create(Models::NewFloatingBPSPrice value) => - new(value); - - public static PriceVariants::NewFloatingBulkBPSPrice Create( - Models::NewFloatingBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewFloatingBulkPrice Create(Models::NewFloatingBulkPrice value) => - new(value); - - public static PriceVariants::NewFloatingThresholdTotalAmountPrice Create( - Models::NewFloatingThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPackagePrice Create( - Models::NewFloatingTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedTieredPrice Create( - Models::NewFloatingGroupedTieredPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMaxGroupTieredPackagePrice Create( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredWithMinimumPrice Create( - Models::NewFloatingTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingPackageWithAllocationPrice Create( - Models::NewFloatingPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPackageWithMinimumPrice Create( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingUnitWithPercentPrice Create( - Models::NewFloatingUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredWithProrationPrice Create( - Models::NewFloatingTieredWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingUnitWithProrationPrice Create( - Models::NewFloatingUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedAllocationPrice Create( - Models::NewFloatingGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedWithProratedMinimumPrice Create( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedWithMeteredMinimumPrice Create( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixWithDisplayNamePrice Create( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewFloatingBulkWithProrationPrice Create( - Models::NewFloatingBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedTieredPackagePrice Create( - Models::NewFloatingGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingScalableMatrixWithUnitPricingPrice Create( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewFloatingScalableMatrixWithTieredPricingPrice Create( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewFloatingCumulativeGroupedBulkPrice Create( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluationProperties/PriceVariants/All.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluationProperties/PriceVariants/All.cs deleted file mode 100644 index ea356350..00000000 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsParamsProperties/PriceEvaluationProperties/PriceVariants/All.cs +++ /dev/null @@ -1,685 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceEvaluationProperties = Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties.PriceEvaluationProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Prices.PriceEvaluatePreviewEventsParamsProperties.PriceEvaluationProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingUnitPrice(Models::NewFloatingUnitPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitPrice From(Models::NewFloatingUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingPackagePrice(Models::NewFloatingPackagePrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingPackagePrice From(Models::NewFloatingPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingMatrixPrice(Models::NewFloatingMatrixPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingMatrixPrice From(Models::NewFloatingMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - >) -)] -public sealed record class NewFloatingMatrixWithAllocationPrice( - Models::NewFloatingMatrixWithAllocationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - > -{ - public static NewFloatingMatrixWithAllocationPrice From( - Models::NewFloatingMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredPrice(Models::NewFloatingTieredPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredPrice From(Models::NewFloatingTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredBPSPrice(Models::NewFloatingTieredBPSPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredBPSPrice From(Models::NewFloatingTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBPSPrice(Models::NewFloatingBPSPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBPSPrice From(Models::NewFloatingBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkBPSPrice(Models::NewFloatingBulkBPSPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkBPSPrice From(Models::NewFloatingBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkPrice(Models::NewFloatingBulkPrice Value) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkPrice From(Models::NewFloatingBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - >) -)] -public sealed record class NewFloatingThresholdTotalAmountPrice( - Models::NewFloatingThresholdTotalAmountPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - > -{ - public static NewFloatingThresholdTotalAmountPrice From( - Models::NewFloatingThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackagePrice, - Models::NewFloatingTieredPackagePrice - >) -)] -public sealed record class NewFloatingTieredPackagePrice( - Models::NewFloatingTieredPackagePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredPackagePrice From(Models::NewFloatingTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPrice, - Models::NewFloatingGroupedTieredPrice - >) -)] -public sealed record class NewFloatingGroupedTieredPrice( - Models::NewFloatingGroupedTieredPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingGroupedTieredPrice From(Models::NewFloatingGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewFloatingMaxGroupTieredPackagePrice( - Models::NewFloatingMaxGroupTieredPackagePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - > -{ - public static NewFloatingMaxGroupTieredPackagePrice From( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithMinimumPrice, - Models::NewFloatingTieredWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredWithMinimumPrice( - Models::NewFloatingTieredWithMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredWithMinimumPrice From( - Models::NewFloatingTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - >) -)] -public sealed record class NewFloatingPackageWithAllocationPrice( - Models::NewFloatingPackageWithAllocationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - > -{ - public static NewFloatingPackageWithAllocationPrice From( - Models::NewFloatingPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredPackageWithMinimumPrice( - Models::NewFloatingTieredPackageWithMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - > -{ - public static NewFloatingTieredPackageWithMinimumPrice From( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithPercentPrice, - Models::NewFloatingUnitWithPercentPrice - >) -)] -public sealed record class NewFloatingUnitWithPercentPrice( - Models::NewFloatingUnitWithPercentPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitWithPercentPrice From( - Models::NewFloatingUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - >) -)] -public sealed record class NewFloatingTieredWithProrationPrice( - Models::NewFloatingTieredWithProrationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - > -{ - public static NewFloatingTieredWithProrationPrice From( - Models::NewFloatingTieredWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithProrationPrice, - Models::NewFloatingUnitWithProrationPrice - >) -)] -public sealed record class NewFloatingUnitWithProrationPrice( - Models::NewFloatingUnitWithProrationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitWithProrationPrice From( - Models::NewFloatingUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedAllocationPrice, - Models::NewFloatingGroupedAllocationPrice - >) -)] -public sealed record class NewFloatingGroupedAllocationPrice( - Models::NewFloatingGroupedAllocationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingGroupedAllocationPrice From( - Models::NewFloatingGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithProratedMinimumPrice( - Models::NewFloatingGroupedWithProratedMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - > -{ - public static NewFloatingGroupedWithProratedMinimumPrice From( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithMeteredMinimumPrice( - Models::NewFloatingGroupedWithMeteredMinimumPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - > -{ - public static NewFloatingGroupedWithMeteredMinimumPrice From( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewFloatingMatrixWithDisplayNamePrice( - Models::NewFloatingMatrixWithDisplayNamePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - > -{ - public static NewFloatingMatrixWithDisplayNamePrice From( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingBulkWithProrationPrice, - Models::NewFloatingBulkWithProrationPrice - >) -)] -public sealed record class NewFloatingBulkWithProrationPrice( - Models::NewFloatingBulkWithProrationPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkWithProrationPrice From( - Models::NewFloatingBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - >) -)] -public sealed record class NewFloatingGroupedTieredPackagePrice( - Models::NewFloatingGroupedTieredPackagePrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - > -{ - public static NewFloatingGroupedTieredPackagePrice From( - Models::NewFloatingGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice( - Models::NewFloatingScalableMatrixWithUnitPricingPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - > -{ - public static NewFloatingScalableMatrixWithUnitPricingPrice From( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice( - Models::NewFloatingScalableMatrixWithTieredPricingPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - > -{ - public static NewFloatingScalableMatrixWithTieredPricingPrice From( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewFloatingCumulativeGroupedBulkPrice( - Models::NewFloatingCumulativeGroupedBulkPrice Value -) - : PriceEvaluationProperties::Price, - Orb::IVariant< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - > -{ - public static NewFloatingCumulativeGroupedBulkPrice From( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponse.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponse.cs index 2e49a1f1..97c5e3e7 100644 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponse.cs +++ b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponse.cs @@ -1,32 +1,33 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PriceEvaluatePreviewEventsResponseProperties = Orb.Models.Prices.PriceEvaluatePreviewEventsResponseProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Prices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceEvaluatePreviewEventsResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsResponse, + PriceEvaluatePreviewEventsResponseFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -37,18 +38,154 @@ public override void Validate() public PriceEvaluatePreviewEventsResponse() { } + public PriceEvaluatePreviewEventsResponse( + PriceEvaluatePreviewEventsResponse priceEvaluatePreviewEventsResponse + ) + : base(priceEvaluatePreviewEventsResponse) { } + + public PriceEvaluatePreviewEventsResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceEvaluatePreviewEventsResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + PriceEvaluatePreviewEventsResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PriceEvaluatePreviewEventsResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceEvaluatePreviewEventsResponse(List data) + : this() + { + this.Data = data; + } +} + +class PriceEvaluatePreviewEventsResponseFromRaw : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluatePreviewEventsResponse.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceEvaluatePreviewEventsResponseData, + PriceEvaluatePreviewEventsResponseDataFromRaw + >) +)] +public sealed record class PriceEvaluatePreviewEventsResponseData : JsonModel +{ + /// + /// The currency of the price + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The computed price groups associated with input price. + /// + public required IReadOnlyList PriceGroups + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "price_groups" + ); + } + init { JsonModel.Set(this._rawData, "price_groups", value); } + } + + /// + /// The external ID of the price + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// The index of the inline price + /// + public long? InlinePriceIndex + { + get { return JsonModel.GetNullableStruct(this.RawData, "inline_price_index"); } + init { JsonModel.Set(this._rawData, "inline_price_index", value); } } + + /// + /// The ID of the price + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.Currency; + foreach (var item in this.PriceGroups) + { + item.Validate(); + } + _ = this.ExternalPriceID; + _ = this.InlinePriceIndex; + _ = this.PriceID; + } + + public PriceEvaluatePreviewEventsResponseData() { } + + public PriceEvaluatePreviewEventsResponseData( + PriceEvaluatePreviewEventsResponseData priceEvaluatePreviewEventsResponseData + ) + : base(priceEvaluatePreviewEventsResponseData) { } + + public PriceEvaluatePreviewEventsResponseData(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceEvaluatePreviewEventsResponseData(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceEvaluatePreviewEventsResponseData FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceEvaluatePreviewEventsResponseDataFromRaw + : IFromRawJson +{ + /// + public PriceEvaluatePreviewEventsResponseData FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluatePreviewEventsResponseData.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponseProperties/Data.cs b/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponseProperties/Data.cs deleted file mode 100644 index 1bb22077..00000000 --- a/src/Orb/Models/Prices/PriceEvaluatePreviewEventsResponseProperties/Data.cs +++ /dev/null @@ -1,130 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Prices = Orb.Models.Prices; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Prices.PriceEvaluatePreviewEventsResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The currency of the price - /// - public required string Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "currency", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("currency"); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The computed price groups associated with input price. - /// - public required Generic::List PriceGroups - { - get - { - if (!this.Properties.TryGetValue("price_groups", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_groups", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("price_groups"); - } - set { this.Properties["price_groups"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external ID of the price - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The index of the inline price - /// - public long? InlinePriceIndex - { - get - { - if (!this.Properties.TryGetValue("inline_price_index", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["inline_price_index"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The ID of the price - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Currency; - foreach (var item in this.PriceGroups) - { - item.Validate(); - } - _ = this.ExternalPriceID; - _ = this.InlinePriceIndex; - _ = this.PriceID; - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Prices/PriceEvaluateResponse.cs b/src/Orb/Models/Prices/PriceEvaluateResponse.cs index 608e91de..cce52d44 100644 --- a/src/Orb/Models/Prices/PriceEvaluateResponse.cs +++ b/src/Orb/Models/Prices/PriceEvaluateResponse.cs @@ -1,30 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Prices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceEvaluateResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceEvaluateResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -35,18 +27,42 @@ public override void Validate() public PriceEvaluateResponse() { } + public PriceEvaluateResponse(PriceEvaluateResponse priceEvaluateResponse) + : base(priceEvaluateResponse) { } + + public PriceEvaluateResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceEvaluateResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + PriceEvaluateResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PriceEvaluateResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + + [SetsRequiredMembers] + public PriceEvaluateResponse(List data) + : this() + { + this.Data = data; + } +} + +class PriceEvaluateResponseFromRaw : IFromRawJson +{ + /// + public PriceEvaluateResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceEvaluateResponse.FromRawUnchecked(rawData); } diff --git a/src/Orb/Models/Prices/PriceFetchParams.cs b/src/Orb/Models/Prices/PriceFetchParams.cs index 8a456ed6..a46837d5 100644 --- a/src/Orb/Models/Prices/PriceFetchParams.cs +++ b/src/Orb/Models/Prices/PriceFetchParams.cs @@ -1,32 +1,74 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Prices; /// /// This endpoint returns a price given an identifier. /// -public sealed record class PriceFetchParams : Orb::ParamsBase +public sealed record class PriceFetchParams : ParamsBase { - public required string PriceID; + public string? PriceID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public PriceFetchParams() { } + + public PriceFetchParams(PriceFetchParams priceFetchParams) + : base(priceFetchParams) { } + + public PriceFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static PriceFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/{0}", this.PriceID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/{0}", this.PriceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Prices/PriceListPage.cs b/src/Orb/Models/Prices/PriceListPage.cs new file mode 100644 index 00000000..e10afb77 --- /dev/null +++ b/src/Orb/Models/Prices/PriceListPage.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; +using Models = Orb.Models; + +namespace Orb.Models.Prices; + +public sealed class PriceListPage( + IPriceService service, + PriceListParams parameters, + PriceListPageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next( + CancellationToken cancellationToken + ) => await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Prices/PriceListPageResponse.cs b/src/Orb/Models/Prices/PriceListPageResponse.cs index 887b05f6..0bf27245 100644 --- a/src/Orb/Models/Prices/PriceListPageResponse.cs +++ b/src/Orb/Models/Prices/PriceListPageResponse.cs @@ -1,50 +1,35 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; namespace Orb.Models.Prices; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class PriceListPageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceListPageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } public required Models::PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -56,18 +41,35 @@ public override void Validate() public PriceListPageResponse() { } + public PriceListPageResponse(PriceListPageResponse priceListPageResponse) + : base(priceListPageResponse) { } + + public PriceListPageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - PriceListPageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + PriceListPageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static PriceListPageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class PriceListPageResponseFromRaw : IFromRawJson +{ + /// + public PriceListPageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceListPageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Prices/PriceListParams.cs b/src/Orb/Models/Prices/PriceListParams.cs index 08523a0b..50054e96 100644 --- a/src/Orb/Models/Prices/PriceListParams.cs +++ b/src/Orb/Models/Prices/PriceListParams.cs @@ -1,14 +1,17 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Prices; /// /// This endpoint is used to list all add-on prices created using the [price creation endpoint](/api-reference/price/create-price). /// -public sealed record class PriceListParams : Orb::ParamsBase +public sealed record class PriceListParams : ParamsBase { /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -16,14 +19,8 @@ public sealed record class PriceListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -31,30 +28,70 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public PriceListParams() { } + + public PriceListParams(PriceListParams priceListParams) + : base(priceListParams) { } + + public PriceListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static PriceListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/prices") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/prices") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Prices/PriceUpdateParams.cs b/src/Orb/Models/Prices/PriceUpdateParams.cs index 7ce83975..b25b005d 100644 --- a/src/Orb/Models/Prices/PriceUpdateParams.cs +++ b/src/Orb/Models/Prices/PriceUpdateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Prices; @@ -11,54 +13,105 @@ namespace Orb.Models.Prices; /// This endpoint allows you to update the `metadata` property on a price. If you /// pass null for the metadata value, it will clear any existing metadata for that price. /// -public sealed record class PriceUpdateParams : Orb::ParamsBase +public sealed record class PriceUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string PriceID; + public string? PriceID { get; init; } /// /// User-specified key/value pairs for the resource. Individual keys can be removed /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } + } + + public PriceUpdateParams() { } + + public PriceUpdateParams(PriceUpdateParams priceUpdateParams) + : base(priceUpdateParams) + { + this._rawBodyData = [.. priceUpdateParams._rawBodyData]; + } + + public PriceUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static PriceUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/{0}", this.PriceID) + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/prices/{0}", this.PriceID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/SharedCreditNote.cs b/src/Orb/Models/SharedCreditNote.cs new file mode 100644 index 00000000..d9a7ccd9 --- /dev/null +++ b/src/Orb/Models/SharedCreditNote.cs @@ -0,0 +1,1048 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models; + +/// +/// The [Credit Note](/invoicing/credit-notes) resource represents a credit that +/// has been applied to a particular invoice. +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class SharedCreditNote : JsonModel +{ + /// + /// The Orb id of this credit note. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The creation time of the resource in Orb. + /// + public required System::DateTimeOffset CreatedAt + { + get + { + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); + } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + /// + /// The unique identifier for credit notes. + /// + public required string CreditNoteNumber + { + get { return JsonModel.GetNotNullClass(this.RawData, "credit_note_number"); } + init { JsonModel.Set(this._rawData, "credit_note_number", value); } + } + + /// + /// A URL to a PDF of the credit note. + /// + public required string? CreditNotePdf + { + get { return JsonModel.GetNullableClass(this.RawData, "credit_note_pdf"); } + init { JsonModel.Set(this._rawData, "credit_note_pdf", value); } + } + + public required CustomerMinified Customer + { + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } + } + + /// + /// The id of the invoice resource that this credit note is applied to. + /// + public required string InvoiceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "invoice_id"); } + init { JsonModel.Set(this._rawData, "invoice_id", value); } + } + + /// + /// All of the line items associated with this credit note. + /// + public required IReadOnlyList LineItems + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "line_items" + ); + } + init { JsonModel.Set(this._rawData, "line_items", value); } + } + + /// + /// The maximum amount applied on the original invoice + /// + public required MaximumAmountAdjustment? MaximumAmountAdjustment + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "maximum_amount_adjustment" + ); + } + init { JsonModel.Set(this._rawData, "maximum_amount_adjustment", value); } + } + + /// + /// An optional memo supplied on the credit note. + /// + public required string? Memo + { + get { return JsonModel.GetNullableClass(this.RawData, "memo"); } + init { JsonModel.Set(this._rawData, "memo", value); } + } + + /// + /// Any credited amount from the applied minimum on the invoice. + /// + public required string? MinimumAmountRefunded + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount_refunded"); } + init { JsonModel.Set(this._rawData, "minimum_amount_refunded", value); } + } + + public required ApiEnum? Reason + { + get { return JsonModel.GetNullableClass>(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + /// + /// The total prior to any creditable invoice-level discounts or minimums. + /// + public required string Subtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } + + /// + /// The total including creditable invoice-level discounts or minimums, and tax. + /// + public required string Total + { + get { return JsonModel.GetNotNullClass(this.RawData, "total"); } + init { JsonModel.Set(this._rawData, "total", value); } + } + + public required ApiEnum Type + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); + } + init { JsonModel.Set(this._rawData, "type", value); } + } + + /// + /// The time at which the credit note was voided in Orb, if applicable. + /// + public required System::DateTimeOffset? VoidedAt + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "voided_at"); + } + init { JsonModel.Set(this._rawData, "voided_at", value); } + } + + /// + /// Any discounts applied on the original invoice. + /// + public IReadOnlyList? Discounts + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "discounts" + ); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "discounts", value); + } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.CreatedAt; + _ = this.CreditNoteNumber; + _ = this.CreditNotePdf; + this.Customer.Validate(); + _ = this.InvoiceID; + foreach (var item in this.LineItems) + { + item.Validate(); + } + this.MaximumAmountAdjustment?.Validate(); + _ = this.Memo; + _ = this.MinimumAmountRefunded; + this.Reason?.Validate(); + _ = this.Subtotal; + _ = this.Total; + this.Type.Validate(); + _ = this.VoidedAt; + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + } + + public SharedCreditNote() { } + + public SharedCreditNote(SharedCreditNote sharedCreditNote) + : base(sharedCreditNote) { } + + public SharedCreditNote(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedCreditNote(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedCreditNote FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedCreditNoteFromRaw : IFromRawJson +{ + /// + public SharedCreditNote FromRawUnchecked(IReadOnlyDictionary rawData) => + SharedCreditNote.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class SharedCreditNoteLineItem : JsonModel +{ + /// + /// The Orb id of this resource. + /// + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// The amount of the line item, including any line item minimums and discounts. + /// + public required string Amount + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } + } + + /// + /// The id of the item associated with this line item. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The name of the corresponding invoice line item. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// An optional quantity credited. + /// + public required double? Quantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + /// The amount of the line item, excluding any line item minimums and discounts. + /// + public required string Subtotal + { + get { return JsonModel.GetNotNullClass(this.RawData, "subtotal"); } + init { JsonModel.Set(this._rawData, "subtotal", value); } + } + + /// + /// Any tax amounts applied onto the line item. + /// + public required IReadOnlyList TaxAmounts + { + get { return JsonModel.GetNotNullClass>(this.RawData, "tax_amounts"); } + init { JsonModel.Set(this._rawData, "tax_amounts", value); } + } + + /// + /// Any line item discounts from the invoice's line item. + /// + public IReadOnlyList? Discounts + { + get { return JsonModel.GetNullableClass>(this.RawData, "discounts"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "discounts", value); + } + } + + /// + /// The end time of the service period for this credit note line item. + /// + public System::DateTimeOffset? EndTimeExclusive + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "end_time_exclusive" + ); + } + init { JsonModel.Set(this._rawData, "end_time_exclusive", value); } + } + + /// + /// The start time of the service period for this credit note line item. + /// + public System::DateTimeOffset? StartTimeInclusive + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "start_time_inclusive" + ); + } + init { JsonModel.Set(this._rawData, "start_time_inclusive", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Amount; + _ = this.ItemID; + _ = this.Name; + _ = this.Quantity; + _ = this.Subtotal; + foreach (var item in this.TaxAmounts) + { + item.Validate(); + } + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + _ = this.EndTimeExclusive; + _ = this.StartTimeInclusive; + } + + public SharedCreditNoteLineItem() { } + + public SharedCreditNoteLineItem(SharedCreditNoteLineItem sharedCreditNoteLineItem) + : base(sharedCreditNoteLineItem) { } + + public SharedCreditNoteLineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedCreditNoteLineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedCreditNoteLineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedCreditNoteLineItemFromRaw : IFromRawJson +{ + /// + public SharedCreditNoteLineItem FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SharedCreditNoteLineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Discount : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string AmountApplied + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount_applied"); } + init { JsonModel.Set(this._rawData, "amount_applied", value); } + } + + public required IReadOnlyList AppliesToPriceIDs + { + get + { + return JsonModel.GetNotNullClass>(this.RawData, "applies_to_price_ids"); + } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } + } + + public required ApiEnum DiscountType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); + } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + public required double PercentageDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } + } + + public string? AmountDiscount + { + get { return JsonModel.GetNullableClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } + } + + public string? Reason + { + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.AmountApplied; + _ = this.AppliesToPriceIDs; + this.DiscountType.Validate(); + _ = this.PercentageDiscount; + _ = this.AmountDiscount; + _ = this.Reason; + } + + public Discount() { } + + public Discount(Discount discount) + : base(discount) { } + + public Discount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Discount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Discount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DiscountFromRaw : IFromRawJson +{ + /// + public Discount FromRawUnchecked(IReadOnlyDictionary rawData) => + Discount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DiscountDiscountTypeConverter))] +public enum DiscountDiscountType +{ + Percentage, + Amount, +} + +sealed class DiscountDiscountTypeConverter : JsonConverter +{ + public override DiscountDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage" => DiscountDiscountType.Percentage, + "amount" => DiscountDiscountType.Amount, + _ => (DiscountDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + DiscountDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + DiscountDiscountType.Percentage => "percentage", + DiscountDiscountType.Amount => "amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The maximum amount applied on the original invoice +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MaximumAmountAdjustment : JsonModel +{ + public required string AmountApplied + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount_applied"); } + init { JsonModel.Set(this._rawData, "amount_applied", value); } + } + + public required ApiEnum DiscountType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); + } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + public required double PercentageDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } + } + + public IReadOnlyList? AppliesToPrices + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_prices" + ); + } + init { JsonModel.Set(this._rawData, "applies_to_prices", value); } + } + + public string? Reason + { + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + /// + public override void Validate() + { + _ = this.AmountApplied; + this.DiscountType.Validate(); + _ = this.PercentageDiscount; + foreach (var item in this.AppliesToPrices ?? []) + { + item.Validate(); + } + _ = this.Reason; + } + + public MaximumAmountAdjustment() { } + + public MaximumAmountAdjustment(MaximumAmountAdjustment maximumAmountAdjustment) + : base(maximumAmountAdjustment) { } + + public MaximumAmountAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaximumAmountAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MaximumAmountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaximumAmountAdjustmentFromRaw : IFromRawJson +{ + /// + public MaximumAmountAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => MaximumAmountAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(MaximumAmountAdjustmentDiscountTypeConverter))] +public enum MaximumAmountAdjustmentDiscountType +{ + Percentage, +} + +sealed class MaximumAmountAdjustmentDiscountTypeConverter + : JsonConverter +{ + public override MaximumAmountAdjustmentDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage" => MaximumAmountAdjustmentDiscountType.Percentage, + _ => (MaximumAmountAdjustmentDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + MaximumAmountAdjustmentDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + MaximumAmountAdjustmentDiscountType.Percentage => "percentage", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AppliesToPrice : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Name; + } + + public AppliesToPrice() { } + + public AppliesToPrice(AppliesToPrice appliesToPrice) + : base(appliesToPrice) { } + + public AppliesToPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AppliesToPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AppliesToPrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AppliesToPriceFromRaw : IFromRawJson +{ + /// + public AppliesToPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + AppliesToPrice.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReasonConverter))] +public enum Reason +{ + Duplicate, + Fraudulent, + OrderChange, + ProductUnsatisfactory, +} + +sealed class ReasonConverter : JsonConverter +{ + public override Reason Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "Duplicate" => Reason.Duplicate, + "Fraudulent" => Reason.Fraudulent, + "Order change" => Reason.OrderChange, + "Product unsatisfactory" => Reason.ProductUnsatisfactory, + _ => (Reason)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Reason value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Reason.Duplicate => "Duplicate", + Reason.Fraudulent => "Fraudulent", + Reason.OrderChange => "Order change", + Reason.ProductUnsatisfactory => "Product unsatisfactory", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(SharedCreditNoteTypeConverter))] +public enum SharedCreditNoteType +{ + Refund, + Adjustment, +} + +sealed class SharedCreditNoteTypeConverter : JsonConverter +{ + public override SharedCreditNoteType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "refund" => SharedCreditNoteType.Refund, + "adjustment" => SharedCreditNoteType.Adjustment, + _ => (SharedCreditNoteType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SharedCreditNoteType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SharedCreditNoteType.Refund => "refund", + SharedCreditNoteType.Adjustment => "adjustment", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class SharedCreditNoteDiscount : JsonModel +{ + public required string AmountApplied + { + get { return JsonModel.GetNotNullClass(this.RawData, "amount_applied"); } + init { JsonModel.Set(this._rawData, "amount_applied", value); } + } + + public required ApiEnum DiscountType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); + } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + public required double PercentageDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } + } + + public IReadOnlyList? AppliesToPrices + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "applies_to_prices" + ); + } + init { JsonModel.Set(this._rawData, "applies_to_prices", value); } + } + + public string? Reason + { + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } + } + + /// + public override void Validate() + { + _ = this.AmountApplied; + this.DiscountType.Validate(); + _ = this.PercentageDiscount; + foreach (var item in this.AppliesToPrices ?? []) + { + item.Validate(); + } + _ = this.Reason; + } + + public SharedCreditNoteDiscount() { } + + public SharedCreditNoteDiscount(SharedCreditNoteDiscount sharedCreditNoteDiscount) + : base(sharedCreditNoteDiscount) { } + + public SharedCreditNoteDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedCreditNoteDiscount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedCreditNoteDiscount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedCreditNoteDiscountFromRaw : IFromRawJson +{ + /// + public SharedCreditNoteDiscount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SharedCreditNoteDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(SharedCreditNoteDiscountDiscountTypeConverter))] +public enum SharedCreditNoteDiscountDiscountType +{ + Percentage, +} + +sealed class SharedCreditNoteDiscountDiscountTypeConverter + : JsonConverter +{ + public override SharedCreditNoteDiscountDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage" => SharedCreditNoteDiscountDiscountType.Percentage, + _ => (SharedCreditNoteDiscountDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SharedCreditNoteDiscountDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SharedCreditNoteDiscountDiscountType.Percentage => "percentage", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SharedCreditNoteDiscountAppliesToPrice, + SharedCreditNoteDiscountAppliesToPriceFromRaw + >) +)] +public sealed record class SharedCreditNoteDiscountAppliesToPrice : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Name; + } + + public SharedCreditNoteDiscountAppliesToPrice() { } + + public SharedCreditNoteDiscountAppliesToPrice( + SharedCreditNoteDiscountAppliesToPrice sharedCreditNoteDiscountAppliesToPrice + ) + : base(sharedCreditNoteDiscountAppliesToPrice) { } + + public SharedCreditNoteDiscountAppliesToPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedCreditNoteDiscountAppliesToPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedCreditNoteDiscountAppliesToPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedCreditNoteDiscountAppliesToPriceFromRaw + : IFromRawJson +{ + /// + public SharedCreditNoteDiscountAppliesToPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SharedCreditNoteDiscountAppliesToPrice.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/SharedDiscount.cs b/src/Orb/Models/SharedDiscount.cs new file mode 100644 index 00000000..9fe79f05 --- /dev/null +++ b/src/Orb/Models/SharedDiscount.cs @@ -0,0 +1,397 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models; + +[JsonConverter(typeof(SharedDiscountConverter))] +public record class SharedDiscount +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Reason + { + get + { + return Match( + percentage: (x) => x.Reason, + trial: (x) => x.Reason, + usage: (x) => x.Reason, + amount: (x) => x.Reason + ); + } + } + + public SharedDiscount(PercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SharedDiscount(TrialDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SharedDiscount(UsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SharedDiscount(AmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SharedDiscount(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `PercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out PercentageDiscount? value) + { + value = this.Value as PercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTrial(out var value)) { + /// // `value` is of type `TrialDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTrial([NotNullWhen(true)] out TrialDiscount? value) + { + value = this.Value as TrialDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUsage(out var value)) { + /// // `value` is of type `UsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUsage([NotNullWhen(true)] out UsageDiscount? value) + { + value = this.Value as UsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `AmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out AmountDiscount? value) + { + value = this.Value as AmountDiscount; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (PercentageDiscount value) => {...}, + /// (TrialDiscount value) => {...}, + /// (UsageDiscount value) => {...}, + /// (AmountDiscount value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action percentage, + System::Action trial, + System::Action usage, + System::Action amount + ) + { + switch (this.Value) + { + case PercentageDiscount value: + percentage(value); + break; + case TrialDiscount value: + trial(value); + break; + case UsageDiscount value: + usage(value); + break; + case AmountDiscount value: + amount(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SharedDiscount" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (PercentageDiscount value) => {...}, + /// (TrialDiscount value) => {...}, + /// (UsageDiscount value) => {...}, + /// (AmountDiscount value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func percentage, + System::Func trial, + System::Func usage, + System::Func amount + ) + { + return this.Value switch + { + PercentageDiscount value => percentage(value), + TrialDiscount value => trial(value), + UsageDiscount value => usage(value), + AmountDiscount value => amount(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SharedDiscount" + ), + }; + } + + public static implicit operator SharedDiscount(PercentageDiscount value) => new(value); + + public static implicit operator SharedDiscount(TrialDiscount value) => new(value); + + public static implicit operator SharedDiscount(UsageDiscount value) => new(value); + + public static implicit operator SharedDiscount(AmountDiscount value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of SharedDiscount"); + } + this.Switch( + (percentage) => percentage.Validate(), + (trial) => trial.Validate(), + (usage) => usage.Validate(), + (amount) => amount.Validate() + ); + } + + public virtual bool Equals(SharedDiscount? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SharedDiscountConverter : JsonConverter +{ + public override SharedDiscount? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); + } + catch + { + discountType = null; + } + + switch (discountType) + { + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "trial": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SharedDiscount(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SharedDiscount value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Models/SharedTier.cs b/src/Orb/Models/SharedTier.cs new file mode 100644 index 00000000..f33dc906 --- /dev/null +++ b/src/Orb/Models/SharedTier.cs @@ -0,0 +1,82 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; + +namespace Orb.Models; + +/// +/// Configuration for a single tier +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class SharedTier : JsonModel +{ + /// + /// Exclusive tier starting value + /// + public required double FirstUnit + { + get { return JsonModel.GetNotNullStruct(this.RawData, "first_unit"); } + init { JsonModel.Set(this._rawData, "first_unit", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// Inclusive tier ending value. This value is null if and only if this is the + /// last tier. + /// + public double? LastUnit + { + get { return JsonModel.GetNullableStruct(this.RawData, "last_unit"); } + init { JsonModel.Set(this._rawData, "last_unit", value); } + } + + /// + public override void Validate() + { + _ = this.FirstUnit; + _ = this.UnitAmount; + _ = this.LastUnit; + } + + public SharedTier() { } + + public SharedTier(SharedTier sharedTier) + : base(sharedTier) { } + + public SharedTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedTier FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedTierFromRaw : IFromRawJson +{ + /// + public SharedTier FromRawUnchecked(IReadOnlyDictionary rawData) => + SharedTier.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/SharedTieredConversionRateConfig.cs b/src/Orb/Models/SharedTieredConversionRateConfig.cs new file mode 100644 index 00000000..9847176e --- /dev/null +++ b/src/Orb/Models/SharedTieredConversionRateConfig.cs @@ -0,0 +1,127 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models; + +[JsonConverter( + typeof(JsonModelConverter< + SharedTieredConversionRateConfig, + SharedTieredConversionRateConfigFromRaw + >) +)] +public sealed record class SharedTieredConversionRateConfig : JsonModel +{ + public required ApiEnum ConversionRateType + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "conversion_rate_type" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_type", value); } + } + + public required ConversionRateTieredConfig TieredConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_config", value); } + } + + /// + public override void Validate() + { + this.ConversionRateType.Validate(); + this.TieredConfig.Validate(); + } + + public SharedTieredConversionRateConfig() { } + + public SharedTieredConversionRateConfig( + SharedTieredConversionRateConfig sharedTieredConversionRateConfig + ) + : base(sharedTieredConversionRateConfig) { } + + public SharedTieredConversionRateConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedTieredConversionRateConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedTieredConversionRateConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedTieredConversionRateConfigFromRaw : IFromRawJson +{ + /// + public SharedTieredConversionRateConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SharedTieredConversionRateConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ConversionRateTypeConverter))] +public enum ConversionRateType +{ + Tiered, +} + +sealed class ConversionRateTypeConverter : JsonConverter +{ + public override ConversionRateType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered" => ConversionRateType.Tiered, + _ => (ConversionRateType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ConversionRateType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ConversionRateType.Tiered => "tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/SharedUnitConversionRateConfig.cs b/src/Orb/Models/SharedUnitConversionRateConfig.cs new file mode 100644 index 00000000..2530bf5b --- /dev/null +++ b/src/Orb/Models/SharedUnitConversionRateConfig.cs @@ -0,0 +1,127 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models; + +[JsonConverter( + typeof(JsonModelConverter< + SharedUnitConversionRateConfig, + SharedUnitConversionRateConfigFromRaw + >) +)] +public sealed record class SharedUnitConversionRateConfig : JsonModel +{ + public required ApiEnum< + string, + SharedUnitConversionRateConfigConversionRateType + > ConversionRateType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "conversion_rate_type"); + } + init { JsonModel.Set(this._rawData, "conversion_rate_type", value); } + } + + public required ConversionRateUnitConfig UnitConfig + { + get + { + return JsonModel.GetNotNullClass(this.RawData, "unit_config"); + } + init { JsonModel.Set(this._rawData, "unit_config", value); } + } + + /// + public override void Validate() + { + this.ConversionRateType.Validate(); + this.UnitConfig.Validate(); + } + + public SharedUnitConversionRateConfig() { } + + public SharedUnitConversionRateConfig( + SharedUnitConversionRateConfig sharedUnitConversionRateConfig + ) + : base(sharedUnitConversionRateConfig) { } + + public SharedUnitConversionRateConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SharedUnitConversionRateConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SharedUnitConversionRateConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SharedUnitConversionRateConfigFromRaw : IFromRawJson +{ + /// + public SharedUnitConversionRateConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SharedUnitConversionRateConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(SharedUnitConversionRateConfigConversionRateTypeConverter))] +public enum SharedUnitConversionRateConfigConversionRateType +{ + Unit, +} + +sealed class SharedUnitConversionRateConfigConversionRateTypeConverter + : JsonConverter +{ + public override SharedUnitConversionRateConfigConversionRateType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit" => SharedUnitConversionRateConfigConversionRateType.Unit, + _ => (SharedUnitConversionRateConfigConversionRateType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SharedUnitConversionRateConfigConversionRateType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SharedUnitConversionRateConfigConversionRateType.Unit => "unit", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/SubLineItemGrouping.cs b/src/Orb/Models/SubLineItemGrouping.cs index 557baf28..26f19f28 100644 --- a/src/Orb/Models/SubLineItemGrouping.cs +++ b/src/Orb/Models/SubLineItemGrouping.cs @@ -1,26 +1,19 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubLineItemGrouping : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class SubLineItemGrouping : JsonModel { public required string Key { - get - { - if (!this.Properties.TryGetValue("key", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("key", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("key"); - } - set { this.Properties["key"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "key"); } + init { JsonModel.Set(this._rawData, "key", value); } } /// @@ -28,16 +21,11 @@ public required string Key /// public required string? Value { - get - { - if (!this.Properties.TryGetValue("value", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("value", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["value"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "value"); } + init { JsonModel.Set(this._rawData, "value", value); } } + /// public override void Validate() { _ = this.Key; @@ -46,18 +34,34 @@ public override void Validate() public SubLineItemGrouping() { } + public SubLineItemGrouping(SubLineItemGrouping subLineItemGrouping) + : base(subLineItemGrouping) { } + + public SubLineItemGrouping(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubLineItemGrouping(Generic::Dictionary properties) + [SetsRequiredMembers] + SubLineItemGrouping(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubLineItemGrouping FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class SubLineItemGroupingFromRaw : IFromRawJson +{ + /// + public SubLineItemGrouping FromRawUnchecked(IReadOnlyDictionary rawData) => + SubLineItemGrouping.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/SubLineItemMatrixConfig.cs b/src/Orb/Models/SubLineItemMatrixConfig.cs index adaef8dd..2e20e5b5 100644 --- a/src/Orb/Models/SubLineItemMatrixConfig.cs +++ b/src/Orb/Models/SubLineItemMatrixConfig.cs @@ -1,61 +1,68 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubLineItemMatrixConfig - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class SubLineItemMatrixConfig : JsonModel { /// /// The ordered dimension values for this line item. /// - public required Generic::List DimensionValues + public required IReadOnlyList DimensionValues { - get - { - if (!this.Properties.TryGetValue("dimension_values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "dimension_values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("dimension_values"); - } - set - { - this.Properties["dimension_values"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass>(this.RawData, "dimension_values"); } + init { JsonModel.Set(this._rawData, "dimension_values", value); } } + /// public override void Validate() { - foreach (var item in this.DimensionValues) - { - _ = item; - } + _ = this.DimensionValues; } public SubLineItemMatrixConfig() { } + public SubLineItemMatrixConfig(SubLineItemMatrixConfig subLineItemMatrixConfig) + : base(subLineItemMatrixConfig) { } + + public SubLineItemMatrixConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubLineItemMatrixConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + SubLineItemMatrixConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubLineItemMatrixConfig FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubLineItemMatrixConfig(List dimensionValues) + : this() + { + this.DimensionValues = dimensionValues; } } + +class SubLineItemMatrixConfigFromRaw : IFromRawJson +{ + /// + public SubLineItemMatrixConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubLineItemMatrixConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/SubscriptionChangeMinified.cs b/src/Orb/Models/SubscriptionChangeMinified.cs index f718aa9e..5aa7969a 100644 --- a/src/Orb/Models/SubscriptionChangeMinified.cs +++ b/src/Orb/Models/SubscriptionChangeMinified.cs @@ -1,30 +1,24 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionChangeMinified - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class SubscriptionChangeMinified : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } + /// public override void Validate() { _ = this.ID; @@ -32,18 +26,42 @@ public override void Validate() public SubscriptionChangeMinified() { } + public SubscriptionChangeMinified(SubscriptionChangeMinified subscriptionChangeMinified) + : base(subscriptionChangeMinified) { } + + public SubscriptionChangeMinified(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionChangeMinified(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionChangeMinified(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionChangeMinified FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionChangeMinified(string id) + : this() + { + this.ID = id; } } + +class SubscriptionChangeMinifiedFromRaw : IFromRawJson +{ + /// + public SubscriptionChangeMinified FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionChangeMinified.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/SubscriptionChanges/MutatedSubscription.cs b/src/Orb/Models/SubscriptionChanges/MutatedSubscription.cs index 8100572f..0691f427 100644 --- a/src/Orb/Models/SubscriptionChanges/MutatedSubscription.cs +++ b/src/Orb/Models/SubscriptionChanges/MutatedSubscription.cs @@ -1,30 +1,23 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Customers = Orb.Models.Customers; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using MutatedSubscriptionProperties = Orb.Models.SubscriptionChanges.MutatedSubscriptionProperties; -using Orb = Orb; -using Plans = Orb.Models.Plans; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Orb.Models.Plans; using System = System; namespace Orb.Models.SubscriptionChanges; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MutatedSubscription : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MutatedSubscription : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -32,53 +25,24 @@ public required string ID /// public required long? ActivePlanPhaseOrder { - get - { - if ( - !this.Properties.TryGetValue( - "active_plan_phase_order", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "active_plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["active_plan_phase_order"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "active_plan_phase_order"); } + init { JsonModel.Set(this._rawData, "active_plan_phase_order", value); } } /// /// The adjustment intervals for this subscription sorted by the start_date of /// the adjustment interval. /// - public required Generic::List AdjustmentIntervals + public required IReadOnlyList AdjustmentIntervals { get { - if (!this.Properties.TryGetValue("adjustment_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustment_intervals"); - } - set - { - this.Properties["adjustment_intervals"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_intervals" ); } + init { JsonModel.Set(this._rawData, "adjustment_intervals", value); } } /// @@ -88,82 +52,41 @@ public required long? ActivePlanPhaseOrder /// public required bool? AutoCollection { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } } - public required Models::BillingCycleAnchorConfiguration BillingCycleAnchorConfiguration + public required BillingCycleAnchorConfiguration BillingCycleAnchorConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_anchor_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_anchor_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("billing_cycle_anchor_configuration"); - } - set - { - this.Properties["billing_cycle_anchor_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_anchor_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_anchor_configuration", value); } } /// /// The day of the month on which the billing cycle is anchored. If the maximum - /// number of days in a month is greater than this value, the last day of the month - /// is the billing cycle day (e.g. billing_cycle_day=31 for April means the billing - /// period begins on the 30th. + /// number of days in a month is greater than this value, the last day of the + /// month is the billing cycle day (e.g. billing_cycle_day=31 for April means + /// the billing period begins on the 30th. /// public required long BillingCycleDay { - get - { - if (!this.Properties.TryGetValue("billing_cycle_day", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_day", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_day"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "billing_cycle_day"); } + init { JsonModel.Set(this._rawData, "billing_cycle_day", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// @@ -171,28 +94,16 @@ public required long BillingCycleDay /// that the instant returned is not part of the billing period. Set to null for /// subscriptions that are not currently active. /// - public required System::DateTime? CurrentBillingPeriodEndDate + public required System::DateTimeOffset? CurrentBillingPeriodEndDate { get { - if ( - !this.Properties.TryGetValue( - "current_billing_period_end_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "current_billing_period_end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["current_billing_period_end_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "current_billing_period_end_date" + ); } + init { JsonModel.Set(this._rawData, "current_billing_period_end_date", value); } } /// @@ -200,194 +111,113 @@ public required long BillingCycleDay /// the instant returned is exactly the beginning of the billing period. Set to /// null if the subscription is not currently active. /// - public required System::DateTime? CurrentBillingPeriodStartDate + public required System::DateTimeOffset? CurrentBillingPeriodStartDate { get { - if ( - !this.Properties.TryGetValue( - "current_billing_period_start_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "current_billing_period_start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["current_billing_period_start_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "current_billing_period_start_date" + ); } + init { JsonModel.Set(this._rawData, "current_billing_period_start_date", value); } } /// /// A customer is a buyer of your products, and the other party to the billing relationship. /// - /// In Orb, customers are assigned system generated identifiers automatically, - /// but it's often desirable to have these match existing identifiers in your system. - /// To avoid having to denormalize Orb ID information, you can pass in an `external_customer_id` - /// with your own identifier. See [Customer ID Aliases](/events-and-metrics/customer-aliases) - /// for further information about how these aliases work in Orb. + /// In Orb, customers are assigned system generated identifiers automatically, + /// but it's often desirable to have these match existing identifiers in your + /// system. To avoid having to denormalize Orb ID information, you can pass in + /// an `external_customer_id` with your own identifier. See [Customer ID Aliases](/events-and-metrics/customer-aliases) + /// for further information about how these aliases work in Orb. /// - /// In addition to having an identifier in your system, a customer may exist in - /// a payment provider solution like Stripe. Use the `payment_provider_id` and the - /// `payment_provider` enum field to express this mapping. + /// In addition to having an identifier in your system, a customer may + /// exist in a payment provider solution like Stripe. Use the `payment_provider_id` + /// and the `payment_provider` enum field to express this mapping. /// - /// A customer also has a timezone (from the standard [IANA timezone database](https://www.iana.org/time-zones)), + /// A customer also has a timezone (from the standard [IANA timezone database](https://www.iana.org/time-zones)), /// which defaults to your account's timezone. See [Timezone localization](/essentials/timezones) - /// for information on what this timezone parameter influences within Orb. + /// for information on what this timezone parameter influences within Orb. /// - public required Customers::Customer Customer + public required Customer Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } /// - /// Determines the default memo on this subscriptions' invoices. Note that if this - /// is not provided, it is determined by the plan configuration. + /// Determines the default memo on this subscriptions' invoices. Note that if + /// this is not provided, it is determined by the plan configuration. /// public required string? DefaultInvoiceMemo { - get - { - if (!this.Properties.TryGetValue("default_invoice_memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "default_invoice_memo", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawData, "default_invoice_memo", value); } } /// /// The discount intervals for this subscription sorted by the start_date. This /// field is deprecated in favor of `adjustment_intervals`. /// - public required Generic::List DiscountIntervals + [System::Obsolete("deprecated")] + public required IReadOnlyList DiscountIntervals { get { - if (!this.Properties.TryGetValue("discount_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("discount_intervals"); - } - set - { - this.Properties["discount_intervals"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_intervals" + ); } + init { JsonModel.Set(this._rawData, "discount_intervals", value); } } /// /// The date Orb stops billing for this subscription. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } - public required Generic::List FixedFeeQuantitySchedule + public required IReadOnlyList FixedFeeQuantitySchedule { get { - if ( - !this.Properties.TryGetValue( - "fixed_fee_quantity_schedule", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "fixed_fee_quantity_schedule", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("fixed_fee_quantity_schedule"); - } - set - { - this.Properties["fixed_fee_quantity_schedule"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "fixed_fee_quantity_schedule" + ); } + init { JsonModel.Set(this._rawData, "fixed_fee_quantity_schedule", value); } } public required string? InvoicingThreshold { - get - { - if (!this.Properties.TryGetValue("invoicing_threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoicing_threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_threshold"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoicing_threshold"); } + init { JsonModel.Set(this._rawData, "invoicing_threshold", value); } } /// /// The maximum intervals for this subscription sorted by the start_date. This /// field is deprecated in favor of `adjustment_intervals`. /// - public required Generic::List MaximumIntervals + [System::Obsolete("deprecated")] + public required IReadOnlyList MaximumIntervals { get { - if (!this.Properties.TryGetValue("maximum_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("maximum_intervals"); - } - set - { - this.Properties["maximum_intervals"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "maximum_intervals" + ); } + init { JsonModel.Set(this._rawData, "maximum_intervals", value); } } /// @@ -396,43 +226,30 @@ public required string? InvoicingThreshold /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// /// The minimum intervals for this subscription sorted by the start_date. This /// field is deprecated in favor of `adjustment_intervals`. /// - public required Generic::List MinimumIntervals + [System::Obsolete("deprecated")] + public required IReadOnlyList MinimumIntervals { get { - if (!this.Properties.TryGetValue("minimum_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("minimum_intervals"); - } - set - { - this.Properties["minimum_intervals"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "minimum_intervals" + ); } + init { JsonModel.Set(this._rawData, "minimum_intervals", value); } } /// @@ -440,164 +257,96 @@ public required string? InvoicingThreshold /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// - /// Determines the difference between the invoice issue date for subscription invoices - /// as the date that they are due. A value of `0` here represents that the invoice - /// is due on issue, whereas a value of `30` represents that the customer has a - /// month to pay the invoice. + /// Determines the difference between the invoice issue date for subscription + /// invoices as the date that they are due. A value of `0` here represents that + /// the invoice is due on issue, whereas a value of `30` represents that the customer + /// has a month to pay the invoice. /// public required long NetTerms { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } } /// /// A pending subscription change if one exists on this subscription. /// - public required Models::SubscriptionChangeMinified? PendingSubscriptionChange + public required SubscriptionChangeMinified? PendingSubscriptionChange { get { - if ( - !this.Properties.TryGetValue( - "pending_subscription_change", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "pending_subscription_change", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["pending_subscription_change"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "pending_subscription_change" + ); } + init { JsonModel.Set(this._rawData, "pending_subscription_change", value); } } /// - /// The [Plan](/core-concepts#plan-and-price) resource represents a plan that can - /// be subscribed to by a customer. Plans define the billing behavior of the subscription. - /// You can see more about how to configure prices in the [Price resource](/reference/price). + /// The [Plan](/core-concepts#plan-and-price) resource represents a plan that + /// can be subscribed to by a customer. Plans define the billing behavior of + /// the subscription. You can see more about how to configure prices in the [Price resource](/reference/price). /// - public required Plans::Plan? Plan + public required Plan? Plan { - get - { - if (!this.Properties.TryGetValue("plan", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("plan", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["plan"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "plan"); } + init { JsonModel.Set(this._rawData, "plan", value); } } /// /// The price intervals for this subscription. /// - public required Generic::List PriceIntervals + public required IReadOnlyList PriceIntervals { get { - if (!this.Properties.TryGetValue("price_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("price_intervals"); + return JsonModel.GetNotNullClass>(this.RawData, "price_intervals"); } - set { this.Properties["price_intervals"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_intervals", value); } } - public required Models::CouponRedemption? RedeemedCoupon + public required CouponRedemption? RedeemedCoupon { get { - if (!this.Properties.TryGetValue("redeemed_coupon", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "redeemed_coupon", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "redeemed_coupon"); } - set { this.Properties["redeemed_coupon"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "redeemed_coupon", value); } } /// /// The date Orb starts billing for this subscription. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } - public required MutatedSubscriptionProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "status"); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required Models::SubscriptionTrialInfo TrialInfo + public required SubscriptionTrialInfo TrialInfo { - get - { - if (!this.Properties.TryGetValue("trial_info", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "trial_info", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("trial_info"); - } - set { this.Properties["trial_info"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "trial_info"); } + init { JsonModel.Set(this._rawData, "trial_info", value); } } /// @@ -605,21 +354,19 @@ public required long NetTerms /// fetched through the subscription changes API or if the `include_changed_resources` /// parameter was passed in the request. /// - public Models::ChangedSubscriptionResources? ChangedResources + public ChangedSubscriptionResources? ChangedResources { get { - if (!this.Properties.TryGetValue("changed_resources", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["changed_resources"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "changed_resources" + ); } + init { JsonModel.Set(this._rawData, "changed_resources", value); } } + /// public override void Validate() { _ = this.ID; @@ -650,10 +397,7 @@ public override void Validate() { item.Validate(); } - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; foreach (var item in this.MinimumIntervals) { item.Validate(); @@ -673,20 +417,446 @@ public override void Validate() this.ChangedResources?.Validate(); } + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] public MutatedSubscription() { } + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] + public MutatedSubscription(MutatedSubscription mutatedSubscription) + : base(mutatedSubscription) { } + + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] + public MutatedSubscription(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MutatedSubscription(Generic::Dictionary properties) + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] + [SetsRequiredMembers] + MutatedSubscription(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static MutatedSubscription FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MutatedSubscriptionFromRaw : IFromRawJson +{ + /// + public MutatedSubscription FromRawUnchecked(IReadOnlyDictionary rawData) => + MutatedSubscription.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DiscountIntervalConverter))] +public record class DiscountInterval +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public System::DateTimeOffset? EndDate + { + get + { + return Match( + amount: (x) => x.EndDate, + percentage: (x) => x.EndDate, + usage: (x) => x.EndDate + ); + } + } + + public System::DateTimeOffset StartDate + { + get + { + return Match( + amount: (x) => x.StartDate, + percentage: (x) => x.StartDate, + usage: (x) => x.StartDate + ); + } + } + + public DiscountInterval(AmountDiscountInterval value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DiscountInterval(PercentageDiscountInterval value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DiscountInterval(UsageDiscountInterval value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DiscountInterval(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `AmountDiscountInterval` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out AmountDiscountInterval? value) + { + value = this.Value as AmountDiscountInterval; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `PercentageDiscountInterval` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out PercentageDiscountInterval? value) + { + value = this.Value as PercentageDiscountInterval; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUsage(out var value)) { + /// // `value` is of type `UsageDiscountInterval` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUsage([NotNullWhen(true)] out UsageDiscountInterval? value) + { + value = this.Value as UsageDiscountInterval; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (AmountDiscountInterval value) => {...}, + /// (PercentageDiscountInterval value) => {...}, + /// (UsageDiscountInterval value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action amount, + System::Action percentage, + System::Action usage + ) + { + switch (this.Value) + { + case AmountDiscountInterval value: + amount(value); + break; + case PercentageDiscountInterval value: + percentage(value); + break; + case UsageDiscountInterval value: + usage(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of DiscountInterval" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (AmountDiscountInterval value) => {...}, + /// (PercentageDiscountInterval value) => {...}, + /// (UsageDiscountInterval value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func amount, + System::Func percentage, + System::Func usage + ) + { + return this.Value switch + { + AmountDiscountInterval value => amount(value), + PercentageDiscountInterval value => percentage(value), + UsageDiscountInterval value => usage(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of DiscountInterval" + ), + }; + } + + public static implicit operator DiscountInterval(AmountDiscountInterval value) => new(value); + + public static implicit operator DiscountInterval(PercentageDiscountInterval value) => + new(value); + + public static implicit operator DiscountInterval(UsageDiscountInterval value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of DiscountInterval"); + } + this.Switch( + (amount) => amount.Validate(), + (percentage) => percentage.Validate(), + (usage) => usage.Validate() + ); + } + + public virtual bool Equals(DiscountInterval? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class DiscountIntervalConverter : JsonConverter +{ + public override DiscountInterval? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); + } + catch + { + discountType = null; + } + + switch (discountType) + { + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new DiscountInterval(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + DiscountInterval value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(global::Orb.Models.SubscriptionChanges.StatusConverter))] +public enum Status +{ + Active, + Ended, + Upcoming, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.SubscriptionChanges.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => global::Orb.Models.SubscriptionChanges.Status.Active, + "ended" => global::Orb.Models.SubscriptionChanges.Status.Ended, + "upcoming" => global::Orb.Models.SubscriptionChanges.Status.Upcoming, + _ => (global::Orb.Models.SubscriptionChanges.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.SubscriptionChanges.Status value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.SubscriptionChanges.Status.Active => "active", + global::Orb.Models.SubscriptionChanges.Status.Ended => "ended", + global::Orb.Models.SubscriptionChanges.Status.Upcoming => "upcoming", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/DiscountInterval.cs b/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/DiscountInterval.cs deleted file mode 100644 index 73194203..00000000 --- a/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/DiscountInterval.cs +++ /dev/null @@ -1,26 +0,0 @@ -using DiscountIntervalVariants = Orb.Models.SubscriptionChanges.MutatedSubscriptionProperties.DiscountIntervalVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.SubscriptionChanges.MutatedSubscriptionProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class DiscountInterval -{ - internal DiscountInterval() { } - - public static DiscountIntervalVariants::AmountDiscountInterval Create( - Models::AmountDiscountInterval value - ) => new(value); - - public static DiscountIntervalVariants::PercentageDiscountInterval Create( - Models::PercentageDiscountInterval value - ) => new(value); - - public static DiscountIntervalVariants::UsageDiscountInterval Create( - Models::UsageDiscountInterval value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/DiscountIntervalVariants/All.cs b/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/DiscountIntervalVariants/All.cs deleted file mode 100644 index e418d0de..00000000 --- a/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/DiscountIntervalVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Models = Orb.Models; -using MutatedSubscriptionProperties = Orb.Models.SubscriptionChanges.MutatedSubscriptionProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.SubscriptionChanges.MutatedSubscriptionProperties.DiscountIntervalVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmountDiscountInterval(Models::AmountDiscountInterval Value) - : MutatedSubscriptionProperties::DiscountInterval, - Orb::IVariant -{ - public static AmountDiscountInterval From(Models::AmountDiscountInterval value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PercentageDiscountInterval(Models::PercentageDiscountInterval Value) - : MutatedSubscriptionProperties::DiscountInterval, - Orb::IVariant -{ - public static PercentageDiscountInterval From(Models::PercentageDiscountInterval value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UsageDiscountInterval(Models::UsageDiscountInterval Value) - : MutatedSubscriptionProperties::DiscountInterval, - Orb::IVariant -{ - public static UsageDiscountInterval From(Models::UsageDiscountInterval value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/Status.cs b/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/Status.cs deleted file mode 100644 index 72c47e2f..00000000 --- a/src/Orb/Models/SubscriptionChanges/MutatedSubscriptionProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.SubscriptionChanges.MutatedSubscriptionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Ended = new("ended"); - - public static readonly Status Upcoming = new("upcoming"); - - readonly string _value = value; - - public enum Value - { - Active, - Ended, - Upcoming, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "ended" => Value.Ended, - "upcoming" => Value.Upcoming, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyParams.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyParams.cs index 529fcf36..dbbd3023 100644 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyParams.cs +++ b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.SubscriptionChanges; @@ -12,77 +14,158 @@ namespace Orb.Models.SubscriptionChanges; /// is passed with a request to this endpoint, any eligible invoices that were created /// will be issued immediately if they only contain in-advance fees. /// -public sealed record class SubscriptionChangeApplyParams : Orb::ParamsBase +public sealed record class SubscriptionChangeApplyParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionChangeID; + public string? SubscriptionChangeID { get; init; } /// /// Description to apply to the balance transaction representing this credit. /// public string? Description + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "description"); } + init { JsonModel.Set(this._rawBodyData, "description", value); } + } + + /// + /// Mark all pending invoices that are payable as paid. If amount is also provided, + /// mark as paid and credit the difference to the customer's balance. + /// + public bool? MarkAsPaid + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "mark_as_paid"); } + init { JsonModel.Set(this._rawBodyData, "mark_as_paid", value); } + } + + /// + /// An optional external ID to associate with the payment. Only applicable when + /// mark_as_paid is true. + /// + public string? PaymentExternalID + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "payment_external_id"); } + init { JsonModel.Set(this._rawBodyData, "payment_external_id", value); } + } + + /// + /// Optional notes about the payment. Only applicable when mark_as_paid is true. + /// + public string? PaymentNotes + { + get { return JsonModel.GetNullableClass(this.RawBodyData, "payment_notes"); } + init { JsonModel.Set(this._rawBodyData, "payment_notes", value); } + } + + /// + /// A date string to specify the date the payment was received. Only applicable + /// when mark_as_paid is true. If not provided, defaults to the current date. + /// + public string? PaymentReceivedDate { get { - if (!this.BodyProperties.TryGetValue("description", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawBodyData, "payment_received_date"); } - set { this.BodyProperties["description"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "payment_received_date", value); } } /// - /// Amount already collected to apply to the customer's balance. + /// Amount already collected to apply to the customer's balance. If mark_as_paid + /// is also provided, credit the difference to the customer's balance. /// public string? PreviouslyCollectedAmount { get { - if ( - !this.BodyProperties.TryGetValue( - "previously_collected_amount", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["previously_collected_amount"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawBodyData, + "previously_collected_amount" + ); } + init { JsonModel.Set(this._rawBodyData, "previously_collected_amount", value); } + } + + public SubscriptionChangeApplyParams() { } + + public SubscriptionChangeApplyParams( + SubscriptionChangeApplyParams subscriptionChangeApplyParams + ) + : base(subscriptionChangeApplyParams) + { + this._rawBodyData = [.. subscriptionChangeApplyParams._rawBodyData]; + } + + public SubscriptionChangeApplyParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionChangeApplyParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionChangeApplyParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscription_changes/{0}/apply", this.SubscriptionChangeID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponse.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponse.cs index fdb02885..622499a5 100644 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponse.cs +++ b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponse.cs @@ -1,140 +1,243 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionChangeApplyResponseProperties = Orb.Models.SubscriptionChanges.SubscriptionChangeApplyResponseProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.SubscriptionChanges; /// -/// A subscription change represents a desired new subscription / pending change -/// to an existing subscription. It is a way to first preview the effects on the subscription +/// A subscription change represents a desired new subscription / pending change to +/// an existing subscription. It is a way to first preview the effects on the subscription /// as well as any changes/creation of invoices (see `subscription.changed_resources`). /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionChangeApplyResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionChangeApplyResponse, + SubscriptionChangeApplyResponseFromRaw + >) +)] +public sealed record class SubscriptionChangeApplyResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// The type of change (e.g., 'schedule_plan_change', 'create_subscription'). + /// + public required string ChangeType + { + get { return JsonModel.GetNotNullClass(this.RawData, "change_type"); } + init { JsonModel.Set(this._rawData, "change_type", value); } } /// /// Subscription change will be cancelled at this time and can no longer be applied. /// - public required System::DateTime ExpirationTime + public required System::DateTimeOffset ExpirationTime { get { - if (!this.Properties.TryGetValue("expiration_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "expiration_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "expiration_time" + ); } - set { this.Properties["expiration_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "expiration_time", value); } } - public required SubscriptionChangeApplyResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "status"); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } public required MutatedSubscription? Subscription { get { - if (!this.Properties.TryGetValue("subscription", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "subscription"); } - set { this.Properties["subscription"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "subscription", value); } } /// /// When this change was applied. /// - public System::DateTime? AppliedAt + public System::DateTimeOffset? AppliedAt { get { - if (!this.Properties.TryGetValue("applied_at", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "applied_at"); } - set { this.Properties["applied_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applied_at", value); } + } + + /// + /// Billing cycle alignment for plan changes. + /// + public string? BillingCycleAlignment + { + get { return JsonModel.GetNullableClass(this.RawData, "billing_cycle_alignment"); } + init { JsonModel.Set(this._rawData, "billing_cycle_alignment", value); } } /// /// When this change was cancelled. /// - public System::DateTime? CancelledAt + public System::DateTimeOffset? CancelledAt { get { - if (!this.Properties.TryGetValue("cancelled_at", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableStruct( + this.RawData, + "cancelled_at" + ); + } + init { JsonModel.Set(this._rawData, "cancelled_at", value); } + } - return Json::JsonSerializer.Deserialize(element); + /// + /// How the change is scheduled (e.g., 'immediate', 'end_of_subscription_term', 'requested_date'). + /// + public string? ChangeOption + { + get { return JsonModel.GetNullableClass(this.RawData, "change_option"); } + init { JsonModel.Set(this._rawData, "change_option", value); } + } + + /// + /// When this change will take effect. + /// + public System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); } - set { this.Properties["cancelled_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "effective_date", value); } } + /// + /// The target plan ID for plan changes. + /// + public string? PlanID + { + get { return JsonModel.GetNullableClass(this.RawData, "plan_id"); } + init { JsonModel.Set(this._rawData, "plan_id", value); } + } + + /// public override void Validate() { _ = this.ID; + _ = this.ChangeType; _ = this.ExpirationTime; this.Status.Validate(); this.Subscription?.Validate(); _ = this.AppliedAt; + _ = this.BillingCycleAlignment; _ = this.CancelledAt; + _ = this.ChangeOption; + _ = this.EffectiveDate; + _ = this.PlanID; } public SubscriptionChangeApplyResponse() { } + public SubscriptionChangeApplyResponse( + SubscriptionChangeApplyResponse subscriptionChangeApplyResponse + ) + : base(subscriptionChangeApplyResponse) { } + + public SubscriptionChangeApplyResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionChangeApplyResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionChangeApplyResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionChangeApplyResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionChangeApplyResponseFromRaw : IFromRawJson +{ + /// + public SubscriptionChangeApplyResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionChangeApplyResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(SubscriptionChangeApplyResponseStatusConverter))] +public enum SubscriptionChangeApplyResponseStatus +{ + Pending, + Applied, + Cancelled, +} + +sealed class SubscriptionChangeApplyResponseStatusConverter + : JsonConverter +{ + public override SubscriptionChangeApplyResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => SubscriptionChangeApplyResponseStatus.Pending, + "applied" => SubscriptionChangeApplyResponseStatus.Applied, + "cancelled" => SubscriptionChangeApplyResponseStatus.Cancelled, + _ => (SubscriptionChangeApplyResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionChangeApplyResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionChangeApplyResponseStatus.Pending => "pending", + SubscriptionChangeApplyResponseStatus.Applied => "applied", + SubscriptionChangeApplyResponseStatus.Cancelled => "cancelled", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponseProperties/Status.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponseProperties/Status.cs deleted file mode 100644 index 45e3cd0d..00000000 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeApplyResponseProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.SubscriptionChanges.SubscriptionChangeApplyResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Applied = new("applied"); - - public static readonly Status Cancelled = new("cancelled"); - - readonly string _value = value; - - public enum Value - { - Pending, - Applied, - Cancelled, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "applied" => Value.Applied, - "cancelled" => Value.Cancelled, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelParams.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelParams.cs index 21dab33d..a9240b93 100644 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelParams.cs +++ b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.SubscriptionChanges; @@ -9,27 +13,67 @@ namespace Orb.Models.SubscriptionChanges; /// can only have one "pending" change at a time - use this endpoint to cancel an /// existing change before creating a new one. /// -public sealed record class SubscriptionChangeCancelParams : Orb::ParamsBase +public sealed record class SubscriptionChangeCancelParams : ParamsBase { - public required string SubscriptionChangeID; + public string? SubscriptionChangeID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionChangeCancelParams() { } + + public SubscriptionChangeCancelParams( + SubscriptionChangeCancelParams subscriptionChangeCancelParams + ) + : base(subscriptionChangeCancelParams) { } + + public SubscriptionChangeCancelParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionChangeCancelParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionChangeCancelParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscription_changes/{0}/cancel", this.SubscriptionChangeID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponse.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponse.cs index 0e3cf5a8..e12430da 100644 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponse.cs +++ b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponse.cs @@ -1,140 +1,243 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionChangeCancelResponseProperties = Orb.Models.SubscriptionChanges.SubscriptionChangeCancelResponseProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.SubscriptionChanges; /// -/// A subscription change represents a desired new subscription / pending change -/// to an existing subscription. It is a way to first preview the effects on the subscription +/// A subscription change represents a desired new subscription / pending change to +/// an existing subscription. It is a way to first preview the effects on the subscription /// as well as any changes/creation of invoices (see `subscription.changed_resources`). /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionChangeCancelResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionChangeCancelResponse, + SubscriptionChangeCancelResponseFromRaw + >) +)] +public sealed record class SubscriptionChangeCancelResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// The type of change (e.g., 'schedule_plan_change', 'create_subscription'). + /// + public required string ChangeType + { + get { return JsonModel.GetNotNullClass(this.RawData, "change_type"); } + init { JsonModel.Set(this._rawData, "change_type", value); } } /// /// Subscription change will be cancelled at this time and can no longer be applied. /// - public required System::DateTime ExpirationTime + public required System::DateTimeOffset ExpirationTime { get { - if (!this.Properties.TryGetValue("expiration_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "expiration_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "expiration_time" + ); } - set { this.Properties["expiration_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "expiration_time", value); } } - public required SubscriptionChangeCancelResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "status"); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } public required MutatedSubscription? Subscription { get { - if (!this.Properties.TryGetValue("subscription", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "subscription"); } - set { this.Properties["subscription"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "subscription", value); } } /// /// When this change was applied. /// - public System::DateTime? AppliedAt + public System::DateTimeOffset? AppliedAt { get { - if (!this.Properties.TryGetValue("applied_at", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "applied_at"); } - set { this.Properties["applied_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applied_at", value); } + } + + /// + /// Billing cycle alignment for plan changes. + /// + public string? BillingCycleAlignment + { + get { return JsonModel.GetNullableClass(this.RawData, "billing_cycle_alignment"); } + init { JsonModel.Set(this._rawData, "billing_cycle_alignment", value); } } /// /// When this change was cancelled. /// - public System::DateTime? CancelledAt + public System::DateTimeOffset? CancelledAt { get { - if (!this.Properties.TryGetValue("cancelled_at", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableStruct( + this.RawData, + "cancelled_at" + ); + } + init { JsonModel.Set(this._rawData, "cancelled_at", value); } + } - return Json::JsonSerializer.Deserialize(element); + /// + /// How the change is scheduled (e.g., 'immediate', 'end_of_subscription_term', 'requested_date'). + /// + public string? ChangeOption + { + get { return JsonModel.GetNullableClass(this.RawData, "change_option"); } + init { JsonModel.Set(this._rawData, "change_option", value); } + } + + /// + /// When this change will take effect. + /// + public System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); } - set { this.Properties["cancelled_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "effective_date", value); } } + /// + /// The target plan ID for plan changes. + /// + public string? PlanID + { + get { return JsonModel.GetNullableClass(this.RawData, "plan_id"); } + init { JsonModel.Set(this._rawData, "plan_id", value); } + } + + /// public override void Validate() { _ = this.ID; + _ = this.ChangeType; _ = this.ExpirationTime; this.Status.Validate(); this.Subscription?.Validate(); _ = this.AppliedAt; + _ = this.BillingCycleAlignment; _ = this.CancelledAt; + _ = this.ChangeOption; + _ = this.EffectiveDate; + _ = this.PlanID; } public SubscriptionChangeCancelResponse() { } + public SubscriptionChangeCancelResponse( + SubscriptionChangeCancelResponse subscriptionChangeCancelResponse + ) + : base(subscriptionChangeCancelResponse) { } + + public SubscriptionChangeCancelResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionChangeCancelResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionChangeCancelResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionChangeCancelResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionChangeCancelResponseFromRaw : IFromRawJson +{ + /// + public SubscriptionChangeCancelResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionChangeCancelResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(SubscriptionChangeCancelResponseStatusConverter))] +public enum SubscriptionChangeCancelResponseStatus +{ + Pending, + Applied, + Cancelled, +} + +sealed class SubscriptionChangeCancelResponseStatusConverter + : JsonConverter +{ + public override SubscriptionChangeCancelResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => SubscriptionChangeCancelResponseStatus.Pending, + "applied" => SubscriptionChangeCancelResponseStatus.Applied, + "cancelled" => SubscriptionChangeCancelResponseStatus.Cancelled, + _ => (SubscriptionChangeCancelResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionChangeCancelResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionChangeCancelResponseStatus.Pending => "pending", + SubscriptionChangeCancelResponseStatus.Applied => "applied", + SubscriptionChangeCancelResponseStatus.Cancelled => "cancelled", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponseProperties/Status.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponseProperties/Status.cs deleted file mode 100644 index da5cdfb4..00000000 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeCancelResponseProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.SubscriptionChanges.SubscriptionChangeCancelResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Applied = new("applied"); - - public static readonly Status Cancelled = new("cancelled"); - - readonly string _value = value; - - public enum Value - { - Pending, - Applied, - Cancelled, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "applied" => Value.Applied, - "cancelled" => Value.Cancelled, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveParams.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveParams.cs index 0e46188e..871a28b3 100644 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveParams.cs +++ b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveParams.cs @@ -1,39 +1,83 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.SubscriptionChanges; /// /// This endpoint returns a subscription change given an identifier. /// -/// A subscription change is created by including `Create-Pending-Subscription-Change: +/// A subscription change is created by including `Create-Pending-Subscription-Change: /// True` in the header of a subscription mutation API call (e.g. [create subscription /// endpoint](/api-reference/subscription/create-subscription), [schedule plan change /// endpoint](/api-reference/subscription/schedule-plan-change), ...). The subscription -/// change will be referenced by the `pending_subscription_change` field in the response. +/// change will be referenced by the `pending_subscription_change` field in the response. /// -public sealed record class SubscriptionChangeRetrieveParams : Orb::ParamsBase +public sealed record class SubscriptionChangeRetrieveParams : ParamsBase { - public required string SubscriptionChangeID; + public string? SubscriptionChangeID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionChangeRetrieveParams() { } + + public SubscriptionChangeRetrieveParams( + SubscriptionChangeRetrieveParams subscriptionChangeRetrieveParams + ) + : base(subscriptionChangeRetrieveParams) { } + + public SubscriptionChangeRetrieveParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionChangeRetrieveParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionChangeRetrieveParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscription_changes/{0}", this.SubscriptionChangeID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponse.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponse.cs index 227d5cc2..53538e6f 100644 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponse.cs +++ b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponse.cs @@ -1,140 +1,243 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionChangeRetrieveResponseProperties = Orb.Models.SubscriptionChanges.SubscriptionChangeRetrieveResponseProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.SubscriptionChanges; /// -/// A subscription change represents a desired new subscription / pending change -/// to an existing subscription. It is a way to first preview the effects on the subscription +/// A subscription change represents a desired new subscription / pending change to +/// an existing subscription. It is a way to first preview the effects on the subscription /// as well as any changes/creation of invoices (see `subscription.changed_resources`). /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionChangeRetrieveResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionChangeRetrieveResponse, + SubscriptionChangeRetrieveResponseFromRaw + >) +)] +public sealed record class SubscriptionChangeRetrieveResponse : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + /// + /// The type of change (e.g., 'schedule_plan_change', 'create_subscription'). + /// + public required string ChangeType + { + get { return JsonModel.GetNotNullClass(this.RawData, "change_type"); } + init { JsonModel.Set(this._rawData, "change_type", value); } } /// /// Subscription change will be cancelled at this time and can no longer be applied. /// - public required System::DateTime ExpirationTime + public required System::DateTimeOffset ExpirationTime { get { - if (!this.Properties.TryGetValue("expiration_time", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "expiration_time", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct( + this.RawData, + "expiration_time" + ); } - set { this.Properties["expiration_time"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "expiration_time", value); } } - public required SubscriptionChangeRetrieveResponseProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "status"); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } public required MutatedSubscription? Subscription { get { - if (!this.Properties.TryGetValue("subscription", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "subscription", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "subscription"); } - set { this.Properties["subscription"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "subscription", value); } } /// /// When this change was applied. /// - public System::DateTime? AppliedAt + public System::DateTimeOffset? AppliedAt { get { - if (!this.Properties.TryGetValue("applied_at", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "applied_at"); } - set { this.Properties["applied_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "applied_at", value); } + } + + /// + /// Billing cycle alignment for plan changes. + /// + public string? BillingCycleAlignment + { + get { return JsonModel.GetNullableClass(this.RawData, "billing_cycle_alignment"); } + init { JsonModel.Set(this._rawData, "billing_cycle_alignment", value); } } /// /// When this change was cancelled. /// - public System::DateTime? CancelledAt + public System::DateTimeOffset? CancelledAt { get { - if (!this.Properties.TryGetValue("cancelled_at", out Json::JsonElement element)) - return null; + return JsonModel.GetNullableStruct( + this.RawData, + "cancelled_at" + ); + } + init { JsonModel.Set(this._rawData, "cancelled_at", value); } + } - return Json::JsonSerializer.Deserialize(element); + /// + /// How the change is scheduled (e.g., 'immediate', 'end_of_subscription_term', 'requested_date'). + /// + public string? ChangeOption + { + get { return JsonModel.GetNullableClass(this.RawData, "change_option"); } + init { JsonModel.Set(this._rawData, "change_option", value); } + } + + /// + /// When this change will take effect. + /// + public System::DateTimeOffset? EffectiveDate + { + get + { + return JsonModel.GetNullableStruct( + this.RawData, + "effective_date" + ); } - set { this.Properties["cancelled_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "effective_date", value); } } + /// + /// The target plan ID for plan changes. + /// + public string? PlanID + { + get { return JsonModel.GetNullableClass(this.RawData, "plan_id"); } + init { JsonModel.Set(this._rawData, "plan_id", value); } + } + + /// public override void Validate() { _ = this.ID; + _ = this.ChangeType; _ = this.ExpirationTime; this.Status.Validate(); this.Subscription?.Validate(); _ = this.AppliedAt; + _ = this.BillingCycleAlignment; _ = this.CancelledAt; + _ = this.ChangeOption; + _ = this.EffectiveDate; + _ = this.PlanID; } public SubscriptionChangeRetrieveResponse() { } + public SubscriptionChangeRetrieveResponse( + SubscriptionChangeRetrieveResponse subscriptionChangeRetrieveResponse + ) + : base(subscriptionChangeRetrieveResponse) { } + + public SubscriptionChangeRetrieveResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionChangeRetrieveResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionChangeRetrieveResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionChangeRetrieveResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionChangeRetrieveResponseFromRaw : IFromRawJson +{ + /// + public SubscriptionChangeRetrieveResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionChangeRetrieveResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(SubscriptionChangeRetrieveResponseStatusConverter))] +public enum SubscriptionChangeRetrieveResponseStatus +{ + Pending, + Applied, + Cancelled, +} + +sealed class SubscriptionChangeRetrieveResponseStatusConverter + : JsonConverter +{ + public override SubscriptionChangeRetrieveResponseStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "pending" => SubscriptionChangeRetrieveResponseStatus.Pending, + "applied" => SubscriptionChangeRetrieveResponseStatus.Applied, + "cancelled" => SubscriptionChangeRetrieveResponseStatus.Cancelled, + _ => (SubscriptionChangeRetrieveResponseStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionChangeRetrieveResponseStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionChangeRetrieveResponseStatus.Pending => "pending", + SubscriptionChangeRetrieveResponseStatus.Applied => "applied", + SubscriptionChangeRetrieveResponseStatus.Cancelled => "cancelled", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponseProperties/Status.cs b/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponseProperties/Status.cs deleted file mode 100644 index 46816061..00000000 --- a/src/Orb/Models/SubscriptionChanges/SubscriptionChangeRetrieveResponseProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.SubscriptionChanges.SubscriptionChangeRetrieveResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Pending = new("pending"); - - public static readonly Status Applied = new("applied"); - - public static readonly Status Cancelled = new("cancelled"); - - readonly string _value = value; - - public enum Value - { - Pending, - Applied, - Cancelled, - } - - public Value Known() => - _value switch - { - "pending" => Value.Pending, - "applied" => Value.Applied, - "cancelled" => Value.Cancelled, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/SubscriptionMinified.cs b/src/Orb/Models/SubscriptionMinified.cs index 2bd4de41..ee589ade 100644 --- a/src/Orb/Models/SubscriptionMinified.cs +++ b/src/Orb/Models/SubscriptionMinified.cs @@ -1,30 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionMinified - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class SubscriptionMinified : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } + /// public override void Validate() { _ = this.ID; @@ -32,18 +24,42 @@ public override void Validate() public SubscriptionMinified() { } + public SubscriptionMinified(SubscriptionMinified subscriptionMinified) + : base(subscriptionMinified) { } + + public SubscriptionMinified(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionMinified(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionMinified(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionMinified FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionMinified(string id) + : this() + { + this.ID = id; } } + +class SubscriptionMinifiedFromRaw : IFromRawJson +{ + /// + public SubscriptionMinified FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionMinified.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/SubscriptionTrialInfo.cs b/src/Orb/Models/SubscriptionTrialInfo.cs index 7fe4cf9d..60075264 100644 --- a/src/Orb/Models/SubscriptionTrialInfo.cs +++ b/src/Orb/Models/SubscriptionTrialInfo.cs @@ -1,32 +1,23 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionTrialInfo - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class SubscriptionTrialInfo : JsonModel { - public required System::DateTime? EndDate + public required DateTimeOffset? EndDate { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } } + /// public override void Validate() { _ = this.EndDate; @@ -34,18 +25,42 @@ public override void Validate() public SubscriptionTrialInfo() { } + public SubscriptionTrialInfo(SubscriptionTrialInfo subscriptionTrialInfo) + : base(subscriptionTrialInfo) { } + + public SubscriptionTrialInfo(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionTrialInfo(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionTrialInfo(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionTrialInfo FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionTrialInfo(DateTimeOffset? endDate) + : this() + { + this.EndDate = endDate; } } + +class SubscriptionTrialInfoFromRaw : IFromRawJson +{ + /// + public SubscriptionTrialInfo FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionTrialInfo.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Subscriptions/DiscountOverride.cs b/src/Orb/Models/Subscriptions/DiscountOverride.cs index a058ee2e..5da96de4 100644 --- a/src/Orb/Models/Subscriptions/DiscountOverride.cs +++ b/src/Orb/Models/Subscriptions/DiscountOverride.cs @@ -1,31 +1,26 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DiscountOverrideProperties = Orb.Models.Subscriptions.DiscountOverrideProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class DiscountOverride : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class DiscountOverride : JsonModel { - public required DiscountOverrideProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "discount_type"); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// @@ -33,33 +28,18 @@ public sealed record class DiscountOverride : Orb::ModelBase, Orb::IFromRaw public string? AmountDiscount { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } } /// - /// Only available if discount_type is `percentage`. This is a number between 0 - /// and 1. + /// Only available if discount_type is `percentage`. This is a number between + /// 0 and 1. /// public double? PercentageDiscount { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } } /// @@ -68,16 +48,11 @@ public double? PercentageDiscount /// public double? UsageDiscount { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } } + /// public override void Validate() { this.DiscountType.Validate(); @@ -88,18 +63,90 @@ public override void Validate() public DiscountOverride() { } + public DiscountOverride(DiscountOverride discountOverride) + : base(discountOverride) { } + + public DiscountOverride(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - DiscountOverride(Generic::Dictionary properties) + [SetsRequiredMembers] + DiscountOverride(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static DiscountOverride FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public DiscountOverride( + ApiEnum discountType + ) + : this() + { + this.DiscountType = discountType; + } +} + +class DiscountOverrideFromRaw : IFromRawJson +{ + /// + public DiscountOverride FromRawUnchecked(IReadOnlyDictionary rawData) => + DiscountOverride.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Subscriptions.DiscountTypeConverter))] +public enum DiscountType +{ + Percentage, + Usage, + Amount, +} + +sealed class DiscountTypeConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.DiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "percentage" => global::Orb.Models.Subscriptions.DiscountType.Percentage, + "usage" => global::Orb.Models.Subscriptions.DiscountType.Usage, + "amount" => global::Orb.Models.Subscriptions.DiscountType.Amount, + _ => (global::Orb.Models.Subscriptions.DiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.DiscountType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.DiscountType.Percentage => "percentage", + global::Orb.Models.Subscriptions.DiscountType.Usage => "usage", + global::Orb.Models.Subscriptions.DiscountType.Amount => "amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Subscriptions/DiscountOverrideProperties/DiscountType.cs b/src/Orb/Models/Subscriptions/DiscountOverrideProperties/DiscountType.cs deleted file mode 100644 index 29dd6b8e..00000000 --- a/src/Orb/Models/Subscriptions/DiscountOverrideProperties/DiscountType.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.DiscountOverrideProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - public static readonly DiscountType Usage = new("usage"); - - public static readonly DiscountType Amount = new("amount"); - - readonly string _value = value; - - public enum Value - { - Percentage, - Usage, - Amount, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - "usage" => Value.Usage, - "amount" => Value.Amount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBPSPrice.cs deleted file mode 100644 index c59c948a..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPrice.cs +++ /dev/null @@ -1,410 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionBPSPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionBPSPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - public required Models::BPSConfig BPSConfig - { - get - { - if (!this.Properties.TryGetValue("bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bps_config"); - } - set { this.Properties["bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The cadence to bill for this price on. - /// - public required NewSubscriptionBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewSubscriptionBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewSubscriptionBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewSubscriptionBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewSubscriptionBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/Cadence.cs deleted file mode 100644 index 219b4070..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index caafd2fd..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 6713783f..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionBPSPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ModelType.cs deleted file mode 100644 index 4959d4e9..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BPS = new("bps"); - - readonly string _value = value; - - public enum Value - { - BPS, - } - - public Value Known() => - _value switch - { - "bps" => Value.BPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPrice.cs deleted file mode 100644 index f07fa808..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPrice.cs +++ /dev/null @@ -1,410 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionBulkBPSPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionBulkBPSPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - public required Models::BulkBPSConfig BulkBPSConfig - { - get - { - if (!this.Properties.TryGetValue("bulk_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_bps_config"); - } - set { this.Properties["bulk_bps_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The cadence to bill for this price on. - /// - public required NewSubscriptionBulkBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewSubscriptionBulkBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewSubscriptionBulkBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BulkBPSConfig.Validate(); - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewSubscriptionBulkBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionBulkBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewSubscriptionBulkBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/Cadence.cs deleted file mode 100644 index 4d780cde..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index da956354..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index e4c4ea8b..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionBulkBPSPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionBulkBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionBulkBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ModelType.cs deleted file mode 100644 index 43576211..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkBPS = new("bulk_bps"); - - readonly string _value = value; - - public enum Value - { - BulkBPS, - } - - public Value Known() => - _value switch - { - "bulk_bps" => Value.BulkBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkPrice.cs index db220cf5..79f01885 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionBulkPrice.cs @@ -1,53 +1,41 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionBulkPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionBulkPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewSubscriptionBulkPrice : JsonModel { - public required Models::BulkConfig BulkConfig + /// + /// Configuration for bulk pricing + /// + public required BulkConfig BulkConfig { - get - { - if (!this.Properties.TryGetValue("bulk_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("bulk_config"); - } - set { this.Properties["bulk_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "bulk_config"); } + init { JsonModel.Set(this._rawData, "bulk_config", value); } } /// /// The cadence to bill for this price on. /// - public required NewSubscriptionBulkPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -55,35 +43,22 @@ public sealed record class NewSubscriptionBulkPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionBulkPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -91,15 +66,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -107,60 +75,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -168,83 +110,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionBulkPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionBulkPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +159,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +168,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,44 +177,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,16 +202,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -353,16 +220,11 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.BulkConfig.Validate(); @@ -381,30 +243,421 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionBulkPrice() { } + public NewSubscriptionBulkPrice(NewSubscriptionBulkPrice newSubscriptionBulkPrice) + : base(newSubscriptionBulkPrice) { } + + public NewSubscriptionBulkPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionBulkPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionBulkPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionBulkPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionBulkPriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionBulkPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionBulkPriceCadenceConverter))] +public enum NewSubscriptionBulkPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionBulkPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionBulkPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionBulkPriceCadence.Annual, + "semi_annual" => NewSubscriptionBulkPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionBulkPriceCadence.Monthly, + "quarterly" => NewSubscriptionBulkPriceCadence.Quarterly, + "one_time" => NewSubscriptionBulkPriceCadence.OneTime, + "custom" => NewSubscriptionBulkPriceCadence.Custom, + _ => (NewSubscriptionBulkPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionBulkPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionBulkPriceCadence.Annual => "annual", + NewSubscriptionBulkPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionBulkPriceCadence.Monthly => "monthly", + NewSubscriptionBulkPriceCadence.Quarterly => "quarterly", + NewSubscriptionBulkPriceCadence.OneTime => "one_time", + NewSubscriptionBulkPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.ModelTypeConverter))] +public enum ModelType +{ + Bulk, +} + +sealed class ModelTypeConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.ModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "bulk" => global::Orb.Models.Subscriptions.ModelType.Bulk, + _ => (global::Orb.Models.Subscriptions.ModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.ModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.ModelType.Bulk => "bulk", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionBulkPriceConversionRateConfigConverter))] +public record class NewSubscriptionBulkPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionBulkPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionBulkPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionBulkPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionBulkPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionBulkPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionBulkPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionBulkPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionBulkPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionBulkPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/Cadence.cs deleted file mode 100644 index 7d3ebcfd..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index f6b5944b..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 178a3964..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionBulkPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ModelType.cs deleted file mode 100644 index 26bfc68a..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Bulk = new("bulk"); - - readonly string _value = value; - - public enum Value - { - Bulk, - } - - public Value Known() => - _value switch - { - "bulk" => Value.Bulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPrice.cs index 93dd6c00..451aa6f3 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPrice.cs @@ -1,64 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionBulkWithProrationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionBulkWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionBulkWithProrationPrice, + NewSubscriptionBulkWithProrationPriceFromRaw + >) +)] +public sealed record class NewSubscriptionBulkWithProrationPrice : JsonModel { - public required Generic::Dictionary BulkWithProrationConfig + /// + /// Configuration for bulk_with_proration pricing + /// + public required global::Orb.Models.Subscriptions.BulkWithProrationConfig BulkWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "bulk_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "bulk_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("bulk_with_proration_config"); - } - set - { - this.Properties["bulk_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_proration_config" ); } + init { JsonModel.Set(this._rawData, "bulk_with_proration_config", value); } } /// /// The cadence to bill for this price on. /// - public required NewSubscriptionBulkWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -66,35 +51,22 @@ public sealed record class NewSubscriptionBulkWithProrationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionBulkWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -102,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -118,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -179,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionBulkWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionBulkWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -364,22 +228,14 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { - foreach (var item in this.BulkWithProrationConfig.Values) - { - _ = item; - } + this.BulkWithProrationConfig.Validate(); this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); @@ -395,30 +251,582 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionBulkWithProrationPrice() { } + public NewSubscriptionBulkWithProrationPrice( + NewSubscriptionBulkWithProrationPrice newSubscriptionBulkWithProrationPrice + ) + : base(newSubscriptionBulkWithProrationPrice) { } + + public NewSubscriptionBulkWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionBulkWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionBulkWithProrationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionBulkWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionBulkWithProrationPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionBulkWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionBulkWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.BulkWithProrationConfig, + global::Orb.Models.Subscriptions.BulkWithProrationConfigFromRaw + >) +)] +public sealed record class BulkWithProrationConfig : JsonModel +{ + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithProrationConfig() { } + + public BulkWithProrationConfig( + global::Orb.Models.Subscriptions.BulkWithProrationConfig bulkWithProrationConfig + ) + : base(bulkWithProrationConfig) { } + + public BulkWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.BulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BulkWithProrationConfig(List tiers) + : this() + { + this.Tiers = tiers; + } +} + +class BulkWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.BulkWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.BulkWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier with proration +/// +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class BulkWithProrationConfigTier : JsonModel +{ + /// + /// Cost per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public BulkWithProrationConfigTier() { } + + public BulkWithProrationConfigTier(BulkWithProrationConfigTier bulkWithProrationConfigTier) + : base(bulkWithProrationConfigTier) { } + + public BulkWithProrationConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BulkWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public BulkWithProrationConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class BulkWithProrationConfigTierFromRaw : IFromRawJson +{ + /// + public BulkWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => BulkWithProrationConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionBulkWithProrationPriceCadenceConverter))] +public enum NewSubscriptionBulkWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionBulkWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionBulkWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionBulkWithProrationPriceCadence.Annual, + "semi_annual" => NewSubscriptionBulkWithProrationPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionBulkWithProrationPriceCadence.Monthly, + "quarterly" => NewSubscriptionBulkWithProrationPriceCadence.Quarterly, + "one_time" => NewSubscriptionBulkWithProrationPriceCadence.OneTime, + "custom" => NewSubscriptionBulkWithProrationPriceCadence.Custom, + _ => (NewSubscriptionBulkWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionBulkWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionBulkWithProrationPriceCadence.Annual => "annual", + NewSubscriptionBulkWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionBulkWithProrationPriceCadence.Monthly => "monthly", + NewSubscriptionBulkWithProrationPriceCadence.Quarterly => "quarterly", + NewSubscriptionBulkWithProrationPriceCadence.OneTime => "one_time", + NewSubscriptionBulkWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionBulkWithProrationPriceModelTypeConverter))] +public enum NewSubscriptionBulkWithProrationPriceModelType +{ + BulkWithProration, +} + +sealed class NewSubscriptionBulkWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionBulkWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "bulk_with_proration" => + NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration, + _ => (NewSubscriptionBulkWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionBulkWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionBulkWithProrationPriceModelType.BulkWithProration => + "bulk_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionBulkWithProrationPriceConversionRateConfigConverter))] +public record class NewSubscriptionBulkWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionBulkWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionBulkWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionBulkWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionBulkWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionBulkWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionBulkWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionBulkWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionBulkWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionBulkWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionBulkWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionBulkWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionBulkWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionBulkWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index 7f398a73..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 74c32349..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 01cfb2a4..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionBulkWithProrationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionBulkWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionBulkWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index 863a4cbb..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionBulkWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionBulkWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType BulkWithProration = new("bulk_with_proration"); - - readonly string _value = value; - - public enum Value - { - BulkWithProration, - } - - public Value Known() => - _value switch - { - "bulk_with_proration" => Value.BulkWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPrice.cs index 5f35dc8b..9c798cd7 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPrice.cs @@ -1,65 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionCumulativeGroupedBulkPriceProperties = Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionCumulativeGroupedBulkPrice, + NewSubscriptionCumulativeGroupedBulkPriceFromRaw + >) )] -public sealed record class NewSubscriptionCumulativeGroupedBulkPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionCumulativeGroupedBulkPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionCumulativeGroupedBulkPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary CumulativeGroupedBulkConfig + /// + /// Configuration for cumulative_grouped_bulk pricing + /// + public required global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfig CumulativeGroupedBulkConfig { get { - if ( - !this.Properties.TryGetValue( - "cumulative_grouped_bulk_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "cumulative_grouped_bulk_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("cumulative_grouped_bulk_config"); - } - set - { - this.Properties["cumulative_grouped_bulk_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_bulk_config" + ); } + init { JsonModel.Set(this._rawData, "cumulative_grouped_bulk_config", value); } } /// @@ -67,35 +51,22 @@ public sealed record class NewSubscriptionCumulativeGroupedBulkPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionCumulativeGroupedBulkPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -103,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionCumulativeGroupedBulkPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,23 +228,15 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.CumulativeGroupedBulkConfig.Values) - { - _ = item; - } + this.CumulativeGroupedBulkConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -396,32 +251,593 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionCumulativeGroupedBulkPrice() { } + + public NewSubscriptionCumulativeGroupedBulkPrice( + NewSubscriptionCumulativeGroupedBulkPrice newSubscriptionCumulativeGroupedBulkPrice + ) + : base(newSubscriptionCumulativeGroupedBulkPrice) { } + + public NewSubscriptionCumulativeGroupedBulkPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionCumulativeGroupedBulkPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionCumulativeGroupedBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionCumulativeGroupedBulkPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionCumulativeGroupedBulkPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionCumulativeGroupedBulkPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionCumulativeGroupedBulkPriceCadenceConverter))] +public enum NewSubscriptionCumulativeGroupedBulkPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionCumulativeGroupedBulkPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionCumulativeGroupedBulkPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual, + "semi_annual" => NewSubscriptionCumulativeGroupedBulkPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionCumulativeGroupedBulkPriceCadence.Monthly, + "quarterly" => NewSubscriptionCumulativeGroupedBulkPriceCadence.Quarterly, + "one_time" => NewSubscriptionCumulativeGroupedBulkPriceCadence.OneTime, + "custom" => NewSubscriptionCumulativeGroupedBulkPriceCadence.Custom, + _ => (NewSubscriptionCumulativeGroupedBulkPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionCumulativeGroupedBulkPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionCumulativeGroupedBulkPriceCadence.Annual => "annual", + NewSubscriptionCumulativeGroupedBulkPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionCumulativeGroupedBulkPriceCadence.Monthly => "monthly", + NewSubscriptionCumulativeGroupedBulkPriceCadence.Quarterly => "quarterly", + NewSubscriptionCumulativeGroupedBulkPriceCadence.OneTime => "one_time", + NewSubscriptionCumulativeGroupedBulkPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_bulk pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfig, + global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedBulkConfig : JsonModel +{ + /// + /// Each tier lower bound must have the same group of values. + /// + public required IReadOnlyList DimensionValues + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "dimension_values" + ); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "dimension_values", value); } } - public NewSubscriptionCumulativeGroupedBulkPrice() { } + /// + /// Grouping key name + /// + public required string Group + { + get { return JsonModel.GetNotNullClass(this.RawData, "group"); } + init { JsonModel.Set(this._rawData, "group", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.DimensionValues) + { + item.Validate(); + } + _ = this.Group; + } + + public CumulativeGroupedBulkConfig() { } + + public CumulativeGroupedBulkConfig( + global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfig cumulativeGroupedBulkConfig + ) + : base(cumulativeGroupedBulkConfig) { } + + public CumulativeGroupedBulkConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionCumulativeGroupedBulkPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + CumulativeGroupedBulkConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedBulkConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.CumulativeGroupedBulkConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a dimension value entry +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.DimensionValue, + global::Orb.Models.Subscriptions.DimensionValueFromRaw + >) +)] +public sealed record class DimensionValue : JsonModel +{ + /// + /// Grouping key value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Unit amount for this combination + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public DimensionValue() { } + + public DimensionValue(global::Orb.Models.Subscriptions.DimensionValue dimensionValue) + : base(dimensionValue) { } + + public DimensionValue(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DimensionValue(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionCumulativeGroupedBulkPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.DimensionValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DimensionValueFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.DimensionValue FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.DimensionValue.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionCumulativeGroupedBulkPriceModelTypeConverter))] +public enum NewSubscriptionCumulativeGroupedBulkPriceModelType +{ + CumulativeGroupedBulk, +} + +sealed class NewSubscriptionCumulativeGroupedBulkPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionCumulativeGroupedBulkPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "cumulative_grouped_bulk" => + NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk, + _ => (NewSubscriptionCumulativeGroupedBulkPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionCumulativeGroupedBulkPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionCumulativeGroupedBulkPriceModelType.CumulativeGroupedBulk => + "cumulative_grouped_bulk", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfigConverter))] +public record class NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionCumulativeGroupedBulkPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/Cadence.cs deleted file mode 100644 index 01ab1efa..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 112e04d4..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index c608f457..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionCumulativeGroupedBulkPriceProperties = Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionCumulativeGroupedBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionCumulativeGroupedBulkPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ModelType.cs deleted file mode 100644 index 1dc1fba3..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionCumulativeGroupedBulkPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionCumulativeGroupedBulkPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType CumulativeGroupedBulk = new("cumulative_grouped_bulk"); - - readonly string _value = value; - - public enum Value - { - CumulativeGroupedBulk, - } - - public Value Known() => - _value switch - { - "cumulative_grouped_bulk" => Value.CumulativeGroupedBulk, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPrice.cs index f67734cb..1be8dd6d 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPrice.cs @@ -1,64 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionGroupedAllocationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionGroupedAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionGroupedAllocationPrice, + NewSubscriptionGroupedAllocationPriceFromRaw + >) +)] +public sealed record class NewSubscriptionGroupedAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionGroupedAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedAllocationConfig + /// + /// Configuration for grouped_allocation pricing + /// + public required global::Orb.Models.Subscriptions.GroupedAllocationConfig GroupedAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_allocation_config"); - } - set - { - this.Properties["grouped_allocation_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_allocation_config" ); } + init { JsonModel.Set(this._rawData, "grouped_allocation_config", value); } } /// @@ -66,35 +51,22 @@ public sealed record class NewSubscriptionGroupedAllocationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionGroupedAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -102,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -118,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -179,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionGroupedAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionGroupedAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -364,23 +228,15 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedAllocationConfig.Values) - { - _ = item; - } + this.GroupedAllocationConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -395,30 +251,511 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionGroupedAllocationPrice() { } + public NewSubscriptionGroupedAllocationPrice( + NewSubscriptionGroupedAllocationPrice newSubscriptionGroupedAllocationPrice + ) + : base(newSubscriptionGroupedAllocationPrice) { } + + public NewSubscriptionGroupedAllocationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionGroupedAllocationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionGroupedAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionGroupedAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionGroupedAllocationPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionGroupedAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionGroupedAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionGroupedAllocationPriceCadenceConverter))] +public enum NewSubscriptionGroupedAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionGroupedAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionGroupedAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionGroupedAllocationPriceCadence.Annual, + "semi_annual" => NewSubscriptionGroupedAllocationPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionGroupedAllocationPriceCadence.Monthly, + "quarterly" => NewSubscriptionGroupedAllocationPriceCadence.Quarterly, + "one_time" => NewSubscriptionGroupedAllocationPriceCadence.OneTime, + "custom" => NewSubscriptionGroupedAllocationPriceCadence.Custom, + _ => (NewSubscriptionGroupedAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedAllocationPriceCadence.Annual => "annual", + NewSubscriptionGroupedAllocationPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionGroupedAllocationPriceCadence.Monthly => "monthly", + NewSubscriptionGroupedAllocationPriceCadence.Quarterly => "quarterly", + NewSubscriptionGroupedAllocationPriceCadence.OneTime => "one_time", + NewSubscriptionGroupedAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedAllocationConfig, + global::Orb.Models.Subscriptions.GroupedAllocationConfigFromRaw + >) +)] +public sealed record class GroupedAllocationConfig : JsonModel +{ + /// + /// Usage allocation per group + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// How to determine the groups that should each be allocated some quantity + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Unit rate for post-allocation + /// + public required string OverageUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "overage_unit_rate"); } + init { JsonModel.Set(this._rawData, "overage_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.GroupingKey; + _ = this.OverageUnitRate; + } + + public GroupedAllocationConfig() { } + + public GroupedAllocationConfig( + global::Orb.Models.Subscriptions.GroupedAllocationConfig groupedAllocationConfig + ) + : base(groupedAllocationConfig) { } + + public GroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedAllocationConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionGroupedAllocationPriceModelTypeConverter))] +public enum NewSubscriptionGroupedAllocationPriceModelType +{ + GroupedAllocation, +} + +sealed class NewSubscriptionGroupedAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionGroupedAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_allocation" => + NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation, + _ => (NewSubscriptionGroupedAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedAllocationPriceModelType.GroupedAllocation => + "grouped_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionGroupedAllocationPriceConversionRateConfigConverter))] +public record class NewSubscriptionGroupedAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionGroupedAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionGroupedAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionGroupedAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionGroupedAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionGroupedAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionGroupedAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionGroupedAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/Cadence.cs deleted file mode 100644 index fdca29b6..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index c1bf93bb..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f8442d0f..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionGroupedAllocationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionGroupedAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionGroupedAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 936fd035..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedAllocation = new("grouped_allocation"); - - readonly string _value = value; - - public enum Value - { - GroupedAllocation, - } - - public Value Known() => - _value switch - { - "grouped_allocation" => Value.GroupedAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePrice.cs index 5c05cba0..12128d68 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePrice.cs @@ -1,65 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionGroupedTieredPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionGroupedTieredPackagePrice, + NewSubscriptionGroupedTieredPackagePriceFromRaw + >) )] -public sealed record class NewSubscriptionGroupedTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionGroupedTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionGroupedTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedTieredPackageConfig + /// + /// Configuration for grouped_tiered_package pricing + /// + public required global::Orb.Models.Subscriptions.GroupedTieredPackageConfig GroupedTieredPackageConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_package_config"); - } - set - { - this.Properties["grouped_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_package_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_tiered_package_config", value); } } /// @@ -67,35 +51,22 @@ public sealed record class NewSubscriptionGroupedTieredPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionGroupedTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -103,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionGroupedTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionGroupedTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,23 +228,15 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedTieredPackageConfig.Values) - { - _ = item; - } + this.GroupedTieredPackageConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -396,32 +251,596 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionGroupedTieredPackagePrice() { } + + public NewSubscriptionGroupedTieredPackagePrice( + NewSubscriptionGroupedTieredPackagePrice newSubscriptionGroupedTieredPackagePrice + ) + : base(newSubscriptionGroupedTieredPackagePrice) { } + + public NewSubscriptionGroupedTieredPackagePrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionGroupedTieredPackagePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionGroupedTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionGroupedTieredPackagePriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionGroupedTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionGroupedTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionGroupedTieredPackagePriceCadenceConverter))] +public enum NewSubscriptionGroupedTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionGroupedTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionGroupedTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionGroupedTieredPackagePriceCadence.Annual, + "semi_annual" => NewSubscriptionGroupedTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewSubscriptionGroupedTieredPackagePriceCadence.Monthly, + "quarterly" => NewSubscriptionGroupedTieredPackagePriceCadence.Quarterly, + "one_time" => NewSubscriptionGroupedTieredPackagePriceCadence.OneTime, + "custom" => NewSubscriptionGroupedTieredPackagePriceCadence.Custom, + _ => (NewSubscriptionGroupedTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionGroupedTieredPackagePriceCadence.Annual => "annual", + NewSubscriptionGroupedTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionGroupedTieredPackagePriceCadence.Monthly => "monthly", + NewSubscriptionGroupedTieredPackagePriceCadence.Quarterly => "quarterly", + NewSubscriptionGroupedTieredPackagePriceCadence.OneTime => "one_time", + NewSubscriptionGroupedTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedTieredPackageConfig, + global::Orb.Models.Subscriptions.GroupedTieredPackageConfigFromRaw + >) +)] +public sealed record class GroupedTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewSubscriptionGroupedTieredPackagePrice() { } + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public GroupedTieredPackageConfig() { } + + public GroupedTieredPackageConfig( + global::Orb.Models.Subscriptions.GroupedTieredPackageConfig groupedTieredPackageConfig + ) + : base(groupedTieredPackageConfig) { } + + public GroupedTieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionGroupedTieredPackagePrice( - Generic::Dictionary properties + [SetsRequiredMembers] + GroupedTieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedTieredPackageConfigTier, + global::Orb.Models.Subscriptions.GroupedTieredPackageConfigTierFromRaw + >) +)] +public sealed record class GroupedTieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public GroupedTieredPackageConfigTier() { } + + public GroupedTieredPackageConfigTier( + global::Orb.Models.Subscriptions.GroupedTieredPackageConfigTier groupedTieredPackageConfigTier ) + : base(groupedTieredPackageConfigTier) { } + + public GroupedTieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredPackageConfigTier(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionGroupedTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.GroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionGroupedTieredPackagePriceModelTypeConverter))] +public enum NewSubscriptionGroupedTieredPackagePriceModelType +{ + GroupedTieredPackage, +} + +sealed class NewSubscriptionGroupedTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionGroupedTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_tiered_package" => + NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage, + _ => (NewSubscriptionGroupedTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedTieredPackagePriceModelType.GroupedTieredPackage => + "grouped_tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionGroupedTieredPackagePriceConversionRateConfigConverter))] +public record class NewSubscriptionGroupedTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionGroupedTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionGroupedTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionGroupedTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionGroupedTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionGroupedTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionGroupedTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionGroupedTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index 90274323..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 8551d004..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 9ae9da86..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionGroupedTieredPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionGroupedTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionGroupedTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index ea1ed09f..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTieredPackage = new("grouped_tiered_package"); - - readonly string _value = value; - - public enum Value - { - GroupedTieredPackage, - } - - public Value Known() => - _value switch - { - "grouped_tiered_package" => Value.GroupedTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPrice.cs index 73cabfc0..ec759dfb 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPrice.cs @@ -1,61 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionGroupedTieredPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionGroupedTieredPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionGroupedTieredPrice, + NewSubscriptionGroupedTieredPriceFromRaw + >) +)] +public sealed record class NewSubscriptionGroupedTieredPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionGroupedTieredPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedTieredConfig + /// + /// Configuration for grouped_tiered pricing + /// + public required global::Orb.Models.Subscriptions.GroupedTieredConfig GroupedTieredConfig { get { - if ( - !this.Properties.TryGetValue("grouped_tiered_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_tiered_config"); - } - set - { - this.Properties["grouped_tiered_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_tiered_config" ); } + init { JsonModel.Set(this._rawData, "grouped_tiered_config", value); } } /// @@ -63,35 +51,22 @@ public sealed record class NewSubscriptionGroupedTieredPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionGroupedTieredPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -99,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -115,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -176,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionGroupedTieredPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionGroupedTieredPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,23 +228,15 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedTieredConfig.Values) - { - _ = item; - } + this.GroupedTieredConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -392,30 +251,580 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionGroupedTieredPrice() { } + public NewSubscriptionGroupedTieredPrice( + NewSubscriptionGroupedTieredPrice newSubscriptionGroupedTieredPrice + ) + : base(newSubscriptionGroupedTieredPrice) { } + + public NewSubscriptionGroupedTieredPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionGroupedTieredPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionGroupedTieredPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionGroupedTieredPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionGroupedTieredPriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionGroupedTieredPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionGroupedTieredPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionGroupedTieredPriceCadenceConverter))] +public enum NewSubscriptionGroupedTieredPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionGroupedTieredPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionGroupedTieredPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionGroupedTieredPriceCadence.Annual, + "semi_annual" => NewSubscriptionGroupedTieredPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionGroupedTieredPriceCadence.Monthly, + "quarterly" => NewSubscriptionGroupedTieredPriceCadence.Quarterly, + "one_time" => NewSubscriptionGroupedTieredPriceCadence.OneTime, + "custom" => NewSubscriptionGroupedTieredPriceCadence.Custom, + _ => (NewSubscriptionGroupedTieredPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedTieredPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedTieredPriceCadence.Annual => "annual", + NewSubscriptionGroupedTieredPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionGroupedTieredPriceCadence.Monthly => "monthly", + NewSubscriptionGroupedTieredPriceCadence.Quarterly => "quarterly", + NewSubscriptionGroupedTieredPriceCadence.OneTime => "one_time", + NewSubscriptionGroupedTieredPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_tiered pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedTieredConfig, + global::Orb.Models.Subscriptions.GroupedTieredConfigFromRaw + >) +)] +public sealed record class GroupedTieredConfig : JsonModel +{ + /// + /// The billable metric property used to group before tiering + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Apply tiered pricing to each segment generated after grouping with the provided key + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public GroupedTieredConfig() { } + + public GroupedTieredConfig( + global::Orb.Models.Subscriptions.GroupedTieredConfig groupedTieredConfig + ) + : base(groupedTieredConfig) { } + + public GroupedTieredConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedTieredConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedTieredConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedTieredConfigTier, + global::Orb.Models.Subscriptions.GroupedTieredConfigTierFromRaw + >) +)] +public sealed record class GroupedTieredConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public GroupedTieredConfigTier() { } + + public GroupedTieredConfigTier( + global::Orb.Models.Subscriptions.GroupedTieredConfigTier groupedTieredConfigTier + ) + : base(groupedTieredConfigTier) { } + + public GroupedTieredConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedTieredConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedTieredConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedTieredConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedTieredConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionGroupedTieredPriceModelTypeConverter))] +public enum NewSubscriptionGroupedTieredPriceModelType +{ + GroupedTiered, +} + +sealed class NewSubscriptionGroupedTieredPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionGroupedTieredPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_tiered" => NewSubscriptionGroupedTieredPriceModelType.GroupedTiered, + _ => (NewSubscriptionGroupedTieredPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedTieredPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedTieredPriceModelType.GroupedTiered => "grouped_tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionGroupedTieredPriceConversionRateConfigConverter))] +public record class NewSubscriptionGroupedTieredPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionGroupedTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedTieredPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedTieredPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedTieredPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionGroupedTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionGroupedTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedTieredPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionGroupedTieredPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionGroupedTieredPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionGroupedTieredPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionGroupedTieredPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedTieredPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/Cadence.cs deleted file mode 100644 index 460392f3..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 8a1a6708..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index dfec9fd2..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionGroupedTieredPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionGroupedTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionGroupedTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ModelType.cs deleted file mode 100644 index 71305eb2..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedTieredPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedTieredPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedTiered = new("grouped_tiered"); - - readonly string _value = value; - - public enum Value - { - GroupedTiered, - } - - public Value Known() => - _value switch - { - "grouped_tiered" => Value.GroupedTiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPrice.cs index 998a1803..d59f62d8 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPrice.cs @@ -1,65 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionGroupedWithMeteredMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionGroupedWithMeteredMinimumPrice, + NewSubscriptionGroupedWithMeteredMinimumPriceFromRaw + >) )] -public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionGroupedWithMeteredMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedWithMeteredMinimumConfig + /// + /// Configuration for grouped_with_metered_minimum pricing + /// + public required global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfig GroupedWithMeteredMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_with_metered_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_metered_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("grouped_with_metered_minimum_config"); - } - set - { - this.Properties["grouped_with_metered_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_metered_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_with_metered_minimum_config", value); } } /// @@ -67,35 +51,25 @@ public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionGroupedWithMeteredMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum< + string, + NewSubscriptionGroupedWithMeteredMinimumPriceModelType + > ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -103,15 +77,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -119,60 +86,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +121,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +170,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +179,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +188,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +213,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,23 +231,15 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedWithMeteredMinimumConfig.Values) - { - _ = item; - } + this.GroupedWithMeteredMinimumConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -396,32 +254,709 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionGroupedWithMeteredMinimumPrice() { } + + public NewSubscriptionGroupedWithMeteredMinimumPrice( + NewSubscriptionGroupedWithMeteredMinimumPrice newSubscriptionGroupedWithMeteredMinimumPrice + ) + : base(newSubscriptionGroupedWithMeteredMinimumPrice) { } + + public NewSubscriptionGroupedWithMeteredMinimumPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionGroupedWithMeteredMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionGroupedWithMeteredMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionGroupedWithMeteredMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionGroupedWithMeteredMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionGroupedWithMeteredMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionGroupedWithMeteredMinimumPriceCadenceConverter))] +public enum NewSubscriptionGroupedWithMeteredMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionGroupedWithMeteredMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionGroupedWithMeteredMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual, + "semi_annual" => NewSubscriptionGroupedWithMeteredMinimumPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Monthly, + "quarterly" => NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Quarterly, + "one_time" => NewSubscriptionGroupedWithMeteredMinimumPriceCadence.OneTime, + "custom" => NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Custom, + _ => (NewSubscriptionGroupedWithMeteredMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedWithMeteredMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Annual => "annual", + NewSubscriptionGroupedWithMeteredMinimumPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Monthly => "monthly", + NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Quarterly => "quarterly", + NewSubscriptionGroupedWithMeteredMinimumPriceCadence.OneTime => "one_time", + NewSubscriptionGroupedWithMeteredMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_metered_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfig, + global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfigFromRaw + >) +)] +public sealed record class GroupedWithMeteredMinimumConfig : JsonModel +{ + /// + /// Used to partition the usage into groups. The minimum amount is applied to + /// each group. + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group per unit + /// + public required string MinimumUnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_unit_amount"); } + init { JsonModel.Set(this._rawData, "minimum_unit_amount", value); } + } + + /// + /// Used to determine the unit rate + /// + public required string PricingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_key"); } + init { JsonModel.Set(this._rawData, "pricing_key", value); } + } + + /// + /// Scale the unit rates by the scaling factor. + /// + public required IReadOnlyList ScalingFactors + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "scaling_factors" + ); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "scaling_factors", value); } } - public NewSubscriptionGroupedWithMeteredMinimumPrice() { } + /// + /// Used to determine the unit rate scaling factor + /// + public required string ScalingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_key"); } + init { JsonModel.Set(this._rawData, "scaling_key", value); } + } + + /// + /// Apply per unit pricing to each pricing value. The minimum amount is applied + /// any unmatched usage. + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "unit_amounts" + ); + } + init { JsonModel.Set(this._rawData, "unit_amounts", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MinimumUnitAmount; + _ = this.PricingKey; + foreach (var item in this.ScalingFactors) + { + item.Validate(); + } + _ = this.ScalingKey; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public GroupedWithMeteredMinimumConfig() { } + + public GroupedWithMeteredMinimumConfig( + global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfig groupedWithMeteredMinimumConfig + ) + : base(groupedWithMeteredMinimumConfig) { } + + public GroupedWithMeteredMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionGroupedWithMeteredMinimumPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + GroupedWithMeteredMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMeteredMinimumConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedWithMeteredMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ScalingFactor, + global::Orb.Models.Subscriptions.ScalingFactorFromRaw + >) +)] +public sealed record class ScalingFactor : JsonModel +{ + /// + /// Scaling factor + /// + public required string ScalingFactorValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Scaling value + /// + public required string ScalingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_value"); } + init { JsonModel.Set(this._rawData, "scaling_value", value); } + } + + /// + public override void Validate() + { + _ = this.ScalingFactorValue; + _ = this.ScalingValue; + } + + public ScalingFactor() { } + + public ScalingFactor(global::Orb.Models.Subscriptions.ScalingFactor scalingFactor) + : base(scalingFactor) { } + + public ScalingFactor(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalingFactor(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionGroupedWithMeteredMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.ScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalingFactorFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.ScalingFactor.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a unit amount +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.UnitAmount, + global::Orb.Models.Subscriptions.UnitAmountFromRaw + >) +)] +public sealed record class UnitAmount : JsonModel +{ + /// + /// Pricing value + /// + public required string PricingValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "pricing_value"); } + init { JsonModel.Set(this._rawData, "pricing_value", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmountValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.PricingValue; + _ = this.UnitAmountValue; + } + + public UnitAmount() { } + + public UnitAmount(global::Orb.Models.Subscriptions.UnitAmount unitAmount) + : base(unitAmount) { } + + public UnitAmount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitAmount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.UnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitAmountFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.UnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.UnitAmount.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionGroupedWithMeteredMinimumPriceModelTypeConverter))] +public enum NewSubscriptionGroupedWithMeteredMinimumPriceModelType +{ + GroupedWithMeteredMinimum, +} + +sealed class NewSubscriptionGroupedWithMeteredMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionGroupedWithMeteredMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_with_metered_minimum" => + NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum, + _ => (NewSubscriptionGroupedWithMeteredMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedWithMeteredMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedWithMeteredMinimumPriceModelType.GroupedWithMeteredMinimum => + "grouped_with_metered_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfigConverter))] +public record class NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedWithMeteredMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/Cadence.cs deleted file mode 100644 index fb988fca..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index c144fe61..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f57018e1..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionGroupedWithMeteredMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionGroupedWithMeteredMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ModelType.cs deleted file mode 100644 index 1b227532..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithMeteredMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithMeteredMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithMeteredMinimum = new( - "grouped_with_metered_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithMeteredMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_metered_minimum" => Value.GroupedWithMeteredMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPrice.cs index 7eb20c38..dd316a84 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPrice.cs @@ -1,66 +1,49 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionGroupedWithProratedMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionGroupedWithProratedMinimumPrice, + NewSubscriptionGroupedWithProratedMinimumPriceFromRaw + >) )] -public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionGroupedWithProratedMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } - public required Generic::Dictionary GroupedWithProratedMinimumConfig + /// + /// Configuration for grouped_with_prorated_minimum pricing + /// + public required global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfig GroupedWithProratedMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "grouped_with_prorated_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "grouped_with_prorated_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException("grouped_with_prorated_minimum_config"); - } - set - { - this.Properties["grouped_with_prorated_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_prorated_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "grouped_with_prorated_minimum_config", value); } } /// @@ -68,35 +51,25 @@ public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionGroupedWithProratedMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum< + string, + NewSubscriptionGroupedWithProratedMinimumPriceModelType + > ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -104,15 +77,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -120,60 +86,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -181,83 +121,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionGroupedWithProratedMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -265,17 +170,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -283,19 +179,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -303,44 +188,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -348,16 +213,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -366,23 +231,15 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); - foreach (var item in this.GroupedWithProratedMinimumConfig.Values) - { - _ = item; - } + this.GroupedWithProratedMinimumConfig.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; @@ -397,32 +254,518 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionGroupedWithProratedMinimumPrice() { } -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionGroupedWithProratedMinimumPrice( - Generic::Dictionary properties + public NewSubscriptionGroupedWithProratedMinimumPrice( + NewSubscriptionGroupedWithProratedMinimumPrice newSubscriptionGroupedWithProratedMinimumPrice + ) + : base(newSubscriptionGroupedWithProratedMinimumPrice) { } + + public NewSubscriptionGroupedWithProratedMinimumPrice( + IReadOnlyDictionary rawData ) { - Properties = properties; + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionGroupedWithProratedMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionGroupedWithProratedMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionGroupedWithProratedMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionGroupedWithProratedMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionGroupedWithProratedMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionGroupedWithProratedMinimumPriceCadenceConverter))] +public enum NewSubscriptionGroupedWithProratedMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionGroupedWithProratedMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionGroupedWithProratedMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual, + "semi_annual" => NewSubscriptionGroupedWithProratedMinimumPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionGroupedWithProratedMinimumPriceCadence.Monthly, + "quarterly" => NewSubscriptionGroupedWithProratedMinimumPriceCadence.Quarterly, + "one_time" => NewSubscriptionGroupedWithProratedMinimumPriceCadence.OneTime, + "custom" => NewSubscriptionGroupedWithProratedMinimumPriceCadence.Custom, + _ => (NewSubscriptionGroupedWithProratedMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedWithProratedMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedWithProratedMinimumPriceCadence.Annual => "annual", + NewSubscriptionGroupedWithProratedMinimumPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionGroupedWithProratedMinimumPriceCadence.Monthly => "monthly", + NewSubscriptionGroupedWithProratedMinimumPriceCadence.Quarterly => "quarterly", + NewSubscriptionGroupedWithProratedMinimumPriceCadence.OneTime => "one_time", + NewSubscriptionGroupedWithProratedMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_prorated_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfig, + global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfigFromRaw + >) +)] +public sealed record class GroupedWithProratedMinimumConfig : JsonModel +{ + /// + /// How to determine the groups that should each have a minimum + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The minimum amount to charge per group + /// + public required string Minimum + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum"); } + init { JsonModel.Set(this._rawData, "minimum", value); } + } + + /// + /// The amount to charge per unit + /// + public required string UnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rate"); } + init { JsonModel.Set(this._rawData, "unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.Minimum; + _ = this.UnitRate; + } + + public GroupedWithProratedMinimumConfig() { } + + public GroupedWithProratedMinimumConfig( + global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfig groupedWithProratedMinimumConfig + ) + : base(groupedWithProratedMinimumConfig) { } + + public GroupedWithProratedMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithProratedMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithProratedMinimumConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.GroupedWithProratedMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionGroupedWithProratedMinimumPriceModelTypeConverter))] +public enum NewSubscriptionGroupedWithProratedMinimumPriceModelType +{ + GroupedWithProratedMinimum, +} + +sealed class NewSubscriptionGroupedWithProratedMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionGroupedWithProratedMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "grouped_with_prorated_minimum" => + NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum, + _ => (NewSubscriptionGroupedWithProratedMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedWithProratedMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionGroupedWithProratedMinimumPriceModelType.GroupedWithProratedMinimum => + "grouped_with_prorated_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfigConverter))] +public record class NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionGroupedWithProratedMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 6b27e6c9..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 55dca971..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 0646b63d..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionGroupedWithProratedMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionGroupedWithProratedMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionGroupedWithProratedMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ModelType.cs deleted file mode 100644 index f9cb6209..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionGroupedWithProratedMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionGroupedWithProratedMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType GroupedWithProratedMinimum = new( - "grouped_with_prorated_minimum" - ); - - readonly string _value = value; - - public enum Value - { - GroupedWithProratedMinimum, - } - - public Value Known() => - _value switch - { - "grouped_with_prorated_minimum" => Value.GroupedWithProratedMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPrice.cs index 547944e1..5707bffc 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPrice.cs @@ -1,37 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionMatrixPriceProperties = Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionMatrixPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewSubscriptionMatrixPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionMatrixPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,51 +34,32 @@ public sealed record class NewSubscriptionMatrixPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Models::MatrixConfig MatrixConfig + /// + /// Configuration for matrix pricing + /// + public required MatrixConfig MatrixConfig { - get - { - if (!this.Properties.TryGetValue("matrix_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "matrix_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_config"); - } - set { this.Properties["matrix_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "matrix_config"); } + init { JsonModel.Set(this._rawData, "matrix_config", value); } } - public required NewSubscriptionMatrixPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -91,15 +67,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -107,60 +76,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -168,83 +111,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionMatrixPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionMatrixPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +160,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +169,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,44 +178,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,16 +203,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -353,16 +221,11 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -381,30 +244,422 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionMatrixPrice() { } + public NewSubscriptionMatrixPrice(NewSubscriptionMatrixPrice newSubscriptionMatrixPrice) + : base(newSubscriptionMatrixPrice) { } + + public NewSubscriptionMatrixPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionMatrixPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionMatrixPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionMatrixPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionMatrixPriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionMatrixPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionMatrixPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionMatrixPriceCadenceConverter))] +public enum NewSubscriptionMatrixPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionMatrixPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionMatrixPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionMatrixPriceCadence.Annual, + "semi_annual" => NewSubscriptionMatrixPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionMatrixPriceCadence.Monthly, + "quarterly" => NewSubscriptionMatrixPriceCadence.Quarterly, + "one_time" => NewSubscriptionMatrixPriceCadence.OneTime, + "custom" => NewSubscriptionMatrixPriceCadence.Custom, + _ => (NewSubscriptionMatrixPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMatrixPriceCadence.Annual => "annual", + NewSubscriptionMatrixPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionMatrixPriceCadence.Monthly => "monthly", + NewSubscriptionMatrixPriceCadence.Quarterly => "quarterly", + NewSubscriptionMatrixPriceCadence.OneTime => "one_time", + NewSubscriptionMatrixPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionMatrixPriceModelTypeConverter))] +public enum NewSubscriptionMatrixPriceModelType +{ + Matrix, +} + +sealed class NewSubscriptionMatrixPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionMatrixPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix" => NewSubscriptionMatrixPriceModelType.Matrix, + _ => (NewSubscriptionMatrixPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMatrixPriceModelType.Matrix => "matrix", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionMatrixPriceConversionRateConfigConverter))] +public record class NewSubscriptionMatrixPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionMatrixPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMatrixPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMatrixPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionMatrixPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionMatrixPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionMatrixPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionMatrixPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionMatrixPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionMatrixPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/Cadence.cs deleted file mode 100644 index e72765c6..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 1352094e..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index a7511893..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionMatrixPriceProperties = Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionMatrixPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionMatrixPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ModelType.cs deleted file mode 100644 index fe4627f0..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Matrix = new("matrix"); - - readonly string _value = value; - - public enum Value - { - Matrix, - } - - public Value Known() => - _value switch - { - "matrix" => Value.Matrix, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPrice.cs index 68281400..e630c676 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPrice.cs @@ -1,39 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionMatrixWithAllocationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionMatrixWithAllocationPrice, + NewSubscriptionMatrixWithAllocationPriceFromRaw + >) )] -public sealed record class NewSubscriptionMatrixWithAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionMatrixWithAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionMatrixWithAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,60 +36,37 @@ public sealed record class NewSubscriptionMatrixWithAllocationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Models::MatrixWithAllocationConfig MatrixWithAllocationConfig + /// + /// Configuration for matrix_with_allocation pricing + /// + public required MatrixWithAllocationConfig MatrixWithAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "matrix_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("matrix_with_allocation_config"); - } - set - { - this.Properties["matrix_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_allocation_config" + ); } + init { JsonModel.Set(this._rawData, "matrix_with_allocation_config", value); } } - public required NewSubscriptionMatrixWithAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -102,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -118,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -179,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionMatrixWithAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionMatrixWithAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -364,16 +228,11 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -392,32 +251,429 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionMatrixWithAllocationPrice() { } -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionMatrixWithAllocationPrice( - Generic::Dictionary properties + public NewSubscriptionMatrixWithAllocationPrice( + NewSubscriptionMatrixWithAllocationPrice newSubscriptionMatrixWithAllocationPrice ) + : base(newSubscriptionMatrixWithAllocationPrice) { } + + public NewSubscriptionMatrixWithAllocationPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionMatrixWithAllocationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionMatrixWithAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionMatrixWithAllocationPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionMatrixWithAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionMatrixWithAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionMatrixWithAllocationPriceCadenceConverter))] +public enum NewSubscriptionMatrixWithAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionMatrixWithAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionMatrixWithAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionMatrixWithAllocationPriceCadence.Annual, + "semi_annual" => NewSubscriptionMatrixWithAllocationPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionMatrixWithAllocationPriceCadence.Monthly, + "quarterly" => NewSubscriptionMatrixWithAllocationPriceCadence.Quarterly, + "one_time" => NewSubscriptionMatrixWithAllocationPriceCadence.OneTime, + "custom" => NewSubscriptionMatrixWithAllocationPriceCadence.Custom, + _ => (NewSubscriptionMatrixWithAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixWithAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMatrixWithAllocationPriceCadence.Annual => "annual", + NewSubscriptionMatrixWithAllocationPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionMatrixWithAllocationPriceCadence.Monthly => "monthly", + NewSubscriptionMatrixWithAllocationPriceCadence.Quarterly => "quarterly", + NewSubscriptionMatrixWithAllocationPriceCadence.OneTime => "one_time", + NewSubscriptionMatrixWithAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionMatrixWithAllocationPriceModelTypeConverter))] +public enum NewSubscriptionMatrixWithAllocationPriceModelType +{ + MatrixWithAllocation, +} + +sealed class NewSubscriptionMatrixWithAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionMatrixWithAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix_with_allocation" => + NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation, + _ => (NewSubscriptionMatrixWithAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixWithAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMatrixWithAllocationPriceModelType.MatrixWithAllocation => + "matrix_with_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionMatrixWithAllocationPriceConversionRateConfigConverter))] +public record class NewSubscriptionMatrixWithAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionMatrixWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMatrixWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMatrixWithAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixWithAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixWithAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionMatrixWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionMatrixWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixWithAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionMatrixWithAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionMatrixWithAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionMatrixWithAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionMatrixWithAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixWithAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/Cadence.cs deleted file mode 100644 index 555fb594..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 5b143992..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index e4311c0e..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionMatrixWithAllocationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionMatrixWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionMatrixWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ModelType.cs deleted file mode 100644 index 42870472..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithAllocation = new("matrix_with_allocation"); - - readonly string _value = value; - - public enum Value - { - MatrixWithAllocation, - } - - public Value Known() => - _value switch - { - "matrix_with_allocation" => Value.MatrixWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePrice.cs index e6283c9e..18591067 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePrice.cs @@ -1,39 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionMatrixWithDisplayNamePriceProperties = Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionMatrixWithDisplayNamePrice, + NewSubscriptionMatrixWithDisplayNamePriceFromRaw + >) )] -public sealed record class NewSubscriptionMatrixWithDisplayNamePrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionMatrixWithDisplayNamePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionMatrixWithDisplayNamePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,61 +36,37 @@ public sealed record class NewSubscriptionMatrixWithDisplayNamePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Generic::Dictionary MatrixWithDisplayNameConfig + /// + /// Configuration for matrix_with_display_name pricing + /// + public required global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfig MatrixWithDisplayNameConfig { get { - if ( - !this.Properties.TryGetValue( - "matrix_with_display_name_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "matrix_with_display_name_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("matrix_with_display_name_config"); - } - set - { - this.Properties["matrix_with_display_name_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "matrix_with_display_name_config" + ); } + init { JsonModel.Set(this._rawData, "matrix_with_display_name_config", value); } } - public required NewSubscriptionMatrixWithDisplayNamePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -103,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionMatrixWithDisplayNamePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,24 +228,16 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; - foreach (var item in this.MatrixWithDisplayNameConfig.Values) - { - _ = item; - } + this.MatrixWithDisplayNameConfig.Validate(); this.ModelType.Validate(); _ = this.Name; _ = this.BillableMetricID; @@ -396,32 +251,598 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionMatrixWithDisplayNamePrice() { } + + public NewSubscriptionMatrixWithDisplayNamePrice( + NewSubscriptionMatrixWithDisplayNamePrice newSubscriptionMatrixWithDisplayNamePrice + ) + : base(newSubscriptionMatrixWithDisplayNamePrice) { } + + public NewSubscriptionMatrixWithDisplayNamePrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionMatrixWithDisplayNamePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionMatrixWithDisplayNamePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionMatrixWithDisplayNamePriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionMatrixWithDisplayNamePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionMatrixWithDisplayNamePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionMatrixWithDisplayNamePriceCadenceConverter))] +public enum NewSubscriptionMatrixWithDisplayNamePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionMatrixWithDisplayNamePriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionMatrixWithDisplayNamePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual, + "semi_annual" => NewSubscriptionMatrixWithDisplayNamePriceCadence.SemiAnnual, + "monthly" => NewSubscriptionMatrixWithDisplayNamePriceCadence.Monthly, + "quarterly" => NewSubscriptionMatrixWithDisplayNamePriceCadence.Quarterly, + "one_time" => NewSubscriptionMatrixWithDisplayNamePriceCadence.OneTime, + "custom" => NewSubscriptionMatrixWithDisplayNamePriceCadence.Custom, + _ => (NewSubscriptionMatrixWithDisplayNamePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixWithDisplayNamePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionMatrixWithDisplayNamePriceCadence.Annual => "annual", + NewSubscriptionMatrixWithDisplayNamePriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionMatrixWithDisplayNamePriceCadence.Monthly => "monthly", + NewSubscriptionMatrixWithDisplayNamePriceCadence.Quarterly => "quarterly", + NewSubscriptionMatrixWithDisplayNamePriceCadence.OneTime => "one_time", + NewSubscriptionMatrixWithDisplayNamePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for matrix_with_display_name pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfig, + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigFromRaw + >) +)] +public sealed record class MatrixWithDisplayNameConfig : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string Dimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension"); } + init { JsonModel.Set(this._rawData, "dimension", value); } + } + + /// + /// Apply per unit pricing to each dimension value + /// + public required IReadOnlyList UnitAmounts + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "unit_amounts"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "unit_amounts", value); } } - public NewSubscriptionMatrixWithDisplayNamePrice() { } + /// + public override void Validate() + { + _ = this.Dimension; + foreach (var item in this.UnitAmounts) + { + item.Validate(); + } + } + + public MatrixWithDisplayNameConfig() { } + + public MatrixWithDisplayNameConfig( + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfig matrixWithDisplayNameConfig + ) + : base(matrixWithDisplayNameConfig) { } + + public MatrixWithDisplayNameConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionMatrixWithDisplayNamePrice( - Generic::Dictionary properties + [SetsRequiredMembers] + MatrixWithDisplayNameConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a unit amount item +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigUnitAmount, + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigUnitAmountFromRaw + >) +)] +public sealed record class MatrixWithDisplayNameConfigUnitAmount : JsonModel +{ + /// + /// The dimension value + /// + public required string DimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "dimension_value"); } + init { JsonModel.Set(this._rawData, "dimension_value", value); } + } + + /// + /// Display name for this dimension value + /// + public required string DisplayName + { + get { return JsonModel.GetNotNullClass(this.RawData, "display_name"); } + init { JsonModel.Set(this._rawData, "display_name", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.DimensionValue; + _ = this.DisplayName; + _ = this.UnitAmount; + } + + public MatrixWithDisplayNameConfigUnitAmount() { } + + public MatrixWithDisplayNameConfigUnitAmount( + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigUnitAmount matrixWithDisplayNameConfigUnitAmount ) + : base(matrixWithDisplayNameConfigUnitAmount) { } + + public MatrixWithDisplayNameConfigUnitAmount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixWithDisplayNameConfigUnitAmount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionMatrixWithDisplayNamePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixWithDisplayNameConfigUnitAmountFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigUnitAmount FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.MatrixWithDisplayNameConfigUnitAmount.FromRawUnchecked( + rawData + ); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionMatrixWithDisplayNamePriceModelTypeConverter))] +public enum NewSubscriptionMatrixWithDisplayNamePriceModelType +{ + MatrixWithDisplayName, +} + +sealed class NewSubscriptionMatrixWithDisplayNamePriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionMatrixWithDisplayNamePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "matrix_with_display_name" => + NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName, + _ => (NewSubscriptionMatrixWithDisplayNamePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixWithDisplayNamePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMatrixWithDisplayNamePriceModelType.MatrixWithDisplayName => + "matrix_with_display_name", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfigConverter))] +public record class NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMatrixWithDisplayNamePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/Cadence.cs deleted file mode 100644 index 2369189b..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index a7731b5d..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 913c69a8..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionMatrixWithDisplayNamePriceProperties = Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionMatrixWithDisplayNamePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionMatrixWithDisplayNamePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ModelType.cs deleted file mode 100644 index 62ed6d3b..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMatrixWithDisplayNamePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMatrixWithDisplayNamePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MatrixWithDisplayName = new("matrix_with_display_name"); - - readonly string _value = value; - - public enum Value - { - MatrixWithDisplayName, - } - - public Value Known() => - _value switch - { - "matrix_with_display_name" => Value.MatrixWithDisplayName, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePrice.cs index 301a7531..ccc14574 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePrice.cs @@ -1,39 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionMaxGroupTieredPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionMaxGroupTieredPackagePrice, + NewSubscriptionMaxGroupTieredPackagePriceFromRaw + >) )] -public sealed record class NewSubscriptionMaxGroupTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionMaxGroupTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionMaxGroupTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,61 +36,37 @@ public sealed record class NewSubscriptionMaxGroupTieredPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required Generic::Dictionary MaxGroupTieredPackageConfig + /// + /// Configuration for max_group_tiered_package pricing + /// + public required global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfig MaxGroupTieredPackageConfig { get { - if ( - !this.Properties.TryGetValue( - "max_group_tiered_package_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "max_group_tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("max_group_tiered_package_config"); - } - set - { - this.Properties["max_group_tiered_package_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "max_group_tiered_package_config" + ); } + init { JsonModel.Set(this._rawData, "max_group_tiered_package_config", value); } } - public required NewSubscriptionMaxGroupTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -103,15 +74,8 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionMaxGroupTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,24 +228,16 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; - foreach (var item in this.MaxGroupTieredPackageConfig.Values) - { - _ = item; - } + this.MaxGroupTieredPackageConfig.Validate(); this.ModelType.Validate(); _ = this.Name; _ = this.BillableMetricID; @@ -396,32 +251,595 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionMaxGroupTieredPackagePrice() { } + + public NewSubscriptionMaxGroupTieredPackagePrice( + NewSubscriptionMaxGroupTieredPackagePrice newSubscriptionMaxGroupTieredPackagePrice + ) + : base(newSubscriptionMaxGroupTieredPackagePrice) { } + + public NewSubscriptionMaxGroupTieredPackagePrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionMaxGroupTieredPackagePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionMaxGroupTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionMaxGroupTieredPackagePriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionMaxGroupTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionMaxGroupTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionMaxGroupTieredPackagePriceCadenceConverter))] +public enum NewSubscriptionMaxGroupTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionMaxGroupTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionMaxGroupTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual, + "semi_annual" => NewSubscriptionMaxGroupTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewSubscriptionMaxGroupTieredPackagePriceCadence.Monthly, + "quarterly" => NewSubscriptionMaxGroupTieredPackagePriceCadence.Quarterly, + "one_time" => NewSubscriptionMaxGroupTieredPackagePriceCadence.OneTime, + "custom" => NewSubscriptionMaxGroupTieredPackagePriceCadence.Custom, + _ => (NewSubscriptionMaxGroupTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMaxGroupTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionMaxGroupTieredPackagePriceCadence.Annual => "annual", + NewSubscriptionMaxGroupTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionMaxGroupTieredPackagePriceCadence.Monthly => "monthly", + NewSubscriptionMaxGroupTieredPackagePriceCadence.Quarterly => "quarterly", + NewSubscriptionMaxGroupTieredPackagePriceCadence.OneTime => "one_time", + NewSubscriptionMaxGroupTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for max_group_tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfig, + global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigFromRaw + >) +)] +public sealed record class MaxGroupTieredPackageConfig : JsonModel +{ + /// + /// The event property used to group before tiering the group with the highest value + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing to the largest group after grouping with the provided key. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewSubscriptionMaxGroupTieredPackagePrice() { } + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public MaxGroupTieredPackageConfig() { } + + public MaxGroupTieredPackageConfig( + global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfig maxGroupTieredPackageConfig + ) + : base(maxGroupTieredPackageConfig) { } + + public MaxGroupTieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionMaxGroupTieredPackagePrice( - Generic::Dictionary properties + [SetsRequiredMembers] + MaxGroupTieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigTier, + global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigTierFromRaw + >) +)] +public sealed record class MaxGroupTieredPackageConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public MaxGroupTieredPackageConfigTier() { } + + public MaxGroupTieredPackageConfigTier( + global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigTier maxGroupTieredPackageConfigTier ) + : base(maxGroupTieredPackageConfigTier) { } + + public MaxGroupTieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MaxGroupTieredPackageConfigTier(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionMaxGroupTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MaxGroupTieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.MaxGroupTieredPackageConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionMaxGroupTieredPackagePriceModelTypeConverter))] +public enum NewSubscriptionMaxGroupTieredPackagePriceModelType +{ + MaxGroupTieredPackage, +} + +sealed class NewSubscriptionMaxGroupTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionMaxGroupTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "max_group_tiered_package" => + NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage, + _ => (NewSubscriptionMaxGroupTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMaxGroupTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMaxGroupTieredPackagePriceModelType.MaxGroupTieredPackage => + "max_group_tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfigConverter))] +public record class NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMaxGroupTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index d74798ff..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 94edac4e..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index cbee70e2..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionMaxGroupTieredPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionMaxGroupTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionMaxGroupTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index db0e2818..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionMaxGroupTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionMaxGroupTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType MaxGroupTieredPackage = new("max_group_tiered_package"); - - readonly string _value = value; - - public enum Value - { - MaxGroupTieredPackage, - } - - public Value Known() => - _value switch - { - "max_group_tiered_package" => Value.MaxGroupTieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionMinimumCompositePrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionMinimumCompositePrice.cs new file mode 100644 index 00000000..a3ba0815 --- /dev/null +++ b/src/Orb/Models/Subscriptions/NewSubscriptionMinimumCompositePrice.cs @@ -0,0 +1,761 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; + +namespace Orb.Models.Subscriptions; + +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionMinimumCompositePrice, + NewSubscriptionMinimumCompositePriceFromRaw + >) +)] +public sealed record class NewSubscriptionMinimumCompositePrice : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// Configuration for minimum pricing + /// + public required global::Orb.Models.Subscriptions.MinimumConfig MinimumConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "minimum_config" + ); + } + init { JsonModel.Set(this._rawData, "minimum_config", value); } + } + + /// + /// The pricing model type + /// + public required ApiEnum ModelType + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); + } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public NewSubscriptionMinimumCompositePriceConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + this.MinimumConfig.Validate(); + this.ModelType.Validate(); + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionMinimumCompositePrice() { } + + public NewSubscriptionMinimumCompositePrice( + NewSubscriptionMinimumCompositePrice newSubscriptionMinimumCompositePrice + ) + : base(newSubscriptionMinimumCompositePrice) { } + + public NewSubscriptionMinimumCompositePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionMinimumCompositePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionMinimumCompositePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionMinimumCompositePriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionMinimumCompositePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionMinimumCompositePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionMinimumCompositePriceCadenceConverter))] +public enum NewSubscriptionMinimumCompositePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionMinimumCompositePriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionMinimumCompositePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionMinimumCompositePriceCadence.Annual, + "semi_annual" => NewSubscriptionMinimumCompositePriceCadence.SemiAnnual, + "monthly" => NewSubscriptionMinimumCompositePriceCadence.Monthly, + "quarterly" => NewSubscriptionMinimumCompositePriceCadence.Quarterly, + "one_time" => NewSubscriptionMinimumCompositePriceCadence.OneTime, + "custom" => NewSubscriptionMinimumCompositePriceCadence.Custom, + _ => (NewSubscriptionMinimumCompositePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMinimumCompositePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMinimumCompositePriceCadence.Annual => "annual", + NewSubscriptionMinimumCompositePriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionMinimumCompositePriceCadence.Monthly => "monthly", + NewSubscriptionMinimumCompositePriceCadence.Quarterly => "quarterly", + NewSubscriptionMinimumCompositePriceCadence.OneTime => "one_time", + NewSubscriptionMinimumCompositePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.MinimumConfig, + global::Orb.Models.Subscriptions.MinimumConfigFromRaw + >) +)] +public sealed record class MinimumConfig : JsonModel +{ + /// + /// The minimum amount to apply + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// If true, subtotals from this price are prorated based on the service period + /// + public bool? Prorated + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorated"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorated", value); + } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.Prorated; + } + + public MinimumConfig() { } + + public MinimumConfig(global::Orb.Models.Subscriptions.MinimumConfig minimumConfig) + : base(minimumConfig) { } + + public MinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.MinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public MinimumConfig(string minimumAmount) + : this() + { + this.MinimumAmount = minimumAmount; + } +} + +class MinimumConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.MinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.MinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionMinimumCompositePriceModelTypeConverter))] +public enum NewSubscriptionMinimumCompositePriceModelType +{ + Minimum, +} + +sealed class NewSubscriptionMinimumCompositePriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionMinimumCompositePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "minimum" => NewSubscriptionMinimumCompositePriceModelType.Minimum, + _ => (NewSubscriptionMinimumCompositePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMinimumCompositePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionMinimumCompositePriceModelType.Minimum => "minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionMinimumCompositePriceConversionRateConfigConverter))] +public record class NewSubscriptionMinimumCompositePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionMinimumCompositePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMinimumCompositePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionMinimumCompositePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMinimumCompositePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMinimumCompositePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionMinimumCompositePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionMinimumCompositePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionMinimumCompositePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionMinimumCompositePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionMinimumCompositePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionMinimumCompositePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionMinimumCompositePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionMinimumCompositePriceConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackagePrice.cs index 6d92382c..af00808e 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionPackagePrice.cs @@ -1,37 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewSubscriptionPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +34,23 @@ public sealed record class NewSubscriptionPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,31 +58,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Models::PackageConfig PackageConfig + /// + /// Configuration for package pricing + /// + public required PackageConfig PackageConfig { - get - { - if (!this.Properties.TryGetValue("package_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("package_config"); - } - set { this.Properties["package_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "package_config"); } + init { JsonModel.Set(this._rawData, "package_config", value); } } /// @@ -107,60 +76,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -168,83 +111,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +160,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +169,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,44 +178,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,16 +203,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -353,16 +221,11 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -381,30 +244,422 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionPackagePrice() { } + public NewSubscriptionPackagePrice(NewSubscriptionPackagePrice newSubscriptionPackagePrice) + : base(newSubscriptionPackagePrice) { } + + public NewSubscriptionPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionPackagePriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionPackagePriceCadenceConverter))] +public enum NewSubscriptionPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionPackagePriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionPackagePriceCadence.Annual, + "semi_annual" => NewSubscriptionPackagePriceCadence.SemiAnnual, + "monthly" => NewSubscriptionPackagePriceCadence.Monthly, + "quarterly" => NewSubscriptionPackagePriceCadence.Quarterly, + "one_time" => NewSubscriptionPackagePriceCadence.OneTime, + "custom" => NewSubscriptionPackagePriceCadence.Custom, + _ => (NewSubscriptionPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionPackagePriceCadence.Annual => "annual", + NewSubscriptionPackagePriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionPackagePriceCadence.Monthly => "monthly", + NewSubscriptionPackagePriceCadence.Quarterly => "quarterly", + NewSubscriptionPackagePriceCadence.OneTime => "one_time", + NewSubscriptionPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionPackagePriceModelTypeConverter))] +public enum NewSubscriptionPackagePriceModelType +{ + Package, +} + +sealed class NewSubscriptionPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "package" => NewSubscriptionPackagePriceModelType.Package, + _ => (NewSubscriptionPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionPackagePriceModelType.Package => "package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionPackagePriceConversionRateConfigConverter))] +public record class NewSubscriptionPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/Cadence.cs deleted file mode 100644 index 3ffb109e..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 963abd44..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index e081906c..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ModelType.cs deleted file mode 100644 index 9b517572..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Package = new("package"); - - readonly string _value = value; - - public enum Value - { - Package, - } - - public Value Known() => - _value switch - { - "package" => Value.Package, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPrice.cs index b3f39bd4..9825812a 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPrice.cs @@ -1,39 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionPackageWithAllocationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionPackageWithAllocationPrice, + NewSubscriptionPackageWithAllocationPriceFromRaw + >) )] -public sealed record class NewSubscriptionPackageWithAllocationPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionPackageWithAllocationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionPackageWithAllocationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,35 +36,22 @@ public sealed record class NewSubscriptionPackageWithAllocationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionPackageWithAllocationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -77,41 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary PackageWithAllocationConfig + /// + /// Configuration for package_with_allocation pricing + /// + public required global::Orb.Models.Subscriptions.PackageWithAllocationConfig PackageWithAllocationConfig { get { - if ( - !this.Properties.TryGetValue( - "package_with_allocation_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "package_with_allocation_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("package_with_allocation_config"); - } - set - { - this.Properties["package_with_allocation_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "package_with_allocation_config" + ); } + init { JsonModel.Set(this._rawData, "package_with_allocation_config", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionPackageWithAllocationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionPackageWithAllocationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.PackageWithAllocationConfig.Values) - { - _ = item; - } + this.PackageWithAllocationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -396,32 +251,513 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionPackageWithAllocationPrice() { } -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionPackageWithAllocationPrice( - Generic::Dictionary properties + public NewSubscriptionPackageWithAllocationPrice( + NewSubscriptionPackageWithAllocationPrice newSubscriptionPackageWithAllocationPrice + ) + : base(newSubscriptionPackageWithAllocationPrice) { } + + public NewSubscriptionPackageWithAllocationPrice( + IReadOnlyDictionary rawData ) { - Properties = properties; + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionPackageWithAllocationPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionPackageWithAllocationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionPackageWithAllocationPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionPackageWithAllocationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionPackageWithAllocationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionPackageWithAllocationPriceCadenceConverter))] +public enum NewSubscriptionPackageWithAllocationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionPackageWithAllocationPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionPackageWithAllocationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionPackageWithAllocationPriceCadence.Annual, + "semi_annual" => NewSubscriptionPackageWithAllocationPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionPackageWithAllocationPriceCadence.Monthly, + "quarterly" => NewSubscriptionPackageWithAllocationPriceCadence.Quarterly, + "one_time" => NewSubscriptionPackageWithAllocationPriceCadence.OneTime, + "custom" => NewSubscriptionPackageWithAllocationPriceCadence.Custom, + _ => (NewSubscriptionPackageWithAllocationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionPackageWithAllocationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionPackageWithAllocationPriceCadence.Annual => "annual", + NewSubscriptionPackageWithAllocationPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionPackageWithAllocationPriceCadence.Monthly => "monthly", + NewSubscriptionPackageWithAllocationPriceCadence.Quarterly => "quarterly", + NewSubscriptionPackageWithAllocationPriceCadence.OneTime => "one_time", + NewSubscriptionPackageWithAllocationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionPackageWithAllocationPriceModelTypeConverter))] +public enum NewSubscriptionPackageWithAllocationPriceModelType +{ + PackageWithAllocation, +} + +sealed class NewSubscriptionPackageWithAllocationPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionPackageWithAllocationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "package_with_allocation" => + NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation, + _ => (NewSubscriptionPackageWithAllocationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionPackageWithAllocationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionPackageWithAllocationPriceModelType.PackageWithAllocation => + "package_with_allocation", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for package_with_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.PackageWithAllocationConfig, + global::Orb.Models.Subscriptions.PackageWithAllocationConfigFromRaw + >) +)] +public sealed record class PackageWithAllocationConfig : JsonModel +{ + /// + /// Usage allocation + /// + public required string Allocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "allocation"); } + init { JsonModel.Set(this._rawData, "allocation", value); } + } + + /// + /// Price per package + /// + public required string PackageAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_amount"); } + init { JsonModel.Set(this._rawData, "package_amount", value); } + } + + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + public override void Validate() + { + _ = this.Allocation; + _ = this.PackageAmount; + _ = this.PackageSize; + } + + public PackageWithAllocationConfig() { } + + public PackageWithAllocationConfig( + global::Orb.Models.Subscriptions.PackageWithAllocationConfig packageWithAllocationConfig + ) + : base(packageWithAllocationConfig) { } + + public PackageWithAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PackageWithAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.PackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PackageWithAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.PackageWithAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.PackageWithAllocationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSubscriptionPackageWithAllocationPriceConversionRateConfigConverter))] +public record class NewSubscriptionPackageWithAllocationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionPackageWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionPackageWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionPackageWithAllocationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionPackageWithAllocationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionPackageWithAllocationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionPackageWithAllocationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionPackageWithAllocationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionPackageWithAllocationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionPackageWithAllocationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionPackageWithAllocationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionPackageWithAllocationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionPackageWithAllocationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionPackageWithAllocationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/Cadence.cs deleted file mode 100644 index f218a6f2..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index c3e2c265..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index e0773867..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionPackageWithAllocationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionPackageWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionPackageWithAllocationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ModelType.cs deleted file mode 100644 index f48aa6a8..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionPackageWithAllocationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionPackageWithAllocationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType PackageWithAllocation = new("package_with_allocation"); - - readonly string _value = value; - - public enum Value - { - PackageWithAllocation, - } - - public Value Known() => - _value switch - { - "package_with_allocation" => Value.PackageWithAllocation, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPrice.cs index aced41b6..2e9ee7f7 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPrice.cs @@ -1,39 +1,37 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionScalableMatrixWithTieredPricingPriceProperties = Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionScalableMatrixWithTieredPricingPrice, + NewSubscriptionScalableMatrixWithTieredPricingPriceFromRaw + >) )] -public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionScalableMatrixWithTieredPricingPriceProperties::Cadence Cadence + public required ApiEnum< + string, + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence + > Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,35 +39,25 @@ public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionScalableMatrixWithTieredPricingPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum< + string, + NewSubscriptionScalableMatrixWithTieredPricingPriceModelType + > ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -77,47 +65,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithTieredPricingConfig + /// + /// Configuration for scalable_matrix_with_tiered_pricing pricing + /// + public required global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfig ScalableMatrixWithTieredPricingConfig { get { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_tiered_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_tiered_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_tiered_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_tiered_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_tiered_pricing_config" + ); } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_tiered_pricing_config", value); } } /// @@ -125,60 +89,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,83 +124,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -270,17 +173,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -288,19 +182,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -308,44 +191,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -353,16 +216,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -371,26 +234,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ScalableMatrixWithTieredPricingConfig.Values) - { - _ = item; - } + this.ScalableMatrixWithTieredPricingConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -402,32 +257,716 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionScalableMatrixWithTieredPricingPrice() { } + public NewSubscriptionScalableMatrixWithTieredPricingPrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice newSubscriptionScalableMatrixWithTieredPricingPrice + ) + : base(newSubscriptionScalableMatrixWithTieredPricingPrice) { } + + public NewSubscriptionScalableMatrixWithTieredPricingPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] + [SetsRequiredMembers] NewSubscriptionScalableMatrixWithTieredPricingPrice( - Generic::Dictionary properties + FrozenDictionary rawData ) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionScalableMatrixWithTieredPricingPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionScalableMatrixWithTieredPricingPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionScalableMatrixWithTieredPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionScalableMatrixWithTieredPricingPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionScalableMatrixWithTieredPricingPriceCadenceConverter))] +public enum NewSubscriptionScalableMatrixWithTieredPricingPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionScalableMatrixWithTieredPricingPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionScalableMatrixWithTieredPricingPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual, + "semi_annual" => NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Monthly, + "quarterly" => NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Quarterly, + "one_time" => NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.OneTime, + "custom" => NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Custom, + _ => (NewSubscriptionScalableMatrixWithTieredPricingPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Annual => "annual", + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.SemiAnnual => + "semi_annual", + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Monthly => "monthly", + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Quarterly => "quarterly", + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.OneTime => "one_time", + NewSubscriptionScalableMatrixWithTieredPricingPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionScalableMatrixWithTieredPricingPriceModelTypeConverter))] +public enum NewSubscriptionScalableMatrixWithTieredPricingPriceModelType +{ + ScalableMatrixWithTieredPricing, +} + +sealed class NewSubscriptionScalableMatrixWithTieredPricingPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionScalableMatrixWithTieredPricingPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "scalable_matrix_with_tiered_pricing" => + NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing, + _ => (NewSubscriptionScalableMatrixWithTieredPricingPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionScalableMatrixWithTieredPricingPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionScalableMatrixWithTieredPricingPriceModelType.ScalableMatrixWithTieredPricing => + "scalable_matrix_with_tiered_pricing", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_tiered_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfig, + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingConfig : JsonModel +{ + /// + /// Used for the scalable matrix first dimension + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); + } + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } + } + + /// + /// Tier pricing structure + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// Used for the scalable matrix second dimension (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.SecondDimension; + } + + public ScalableMatrixWithTieredPricingConfig() { } + + public ScalableMatrixWithTieredPricingConfig( + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfig scalableMatrixWithTieredPricingConfig + ) + : base(scalableMatrixWithTieredPricingConfig) { } + + public ScalableMatrixWithTieredPricingConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.MatrixScalingFactor, + global::Orb.Models.Subscriptions.MatrixScalingFactorFromRaw + >) +)] +public sealed record class MatrixScalingFactor : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public MatrixScalingFactor() { } + + public MatrixScalingFactor( + global::Orb.Models.Subscriptions.MatrixScalingFactor matrixScalingFactor + ) + : base(matrixScalingFactor) { } + + public MatrixScalingFactor(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MatrixScalingFactor(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.MatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.MatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.MatrixScalingFactor.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier entry with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigTier, + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigTierFromRaw + >) +)] +public sealed record class ScalableMatrixWithTieredPricingConfigTier : JsonModel +{ + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public ScalableMatrixWithTieredPricingConfigTier() { } + + public ScalableMatrixWithTieredPricingConfigTier( + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigTier scalableMatrixWithTieredPricingConfigTier + ) + : base(scalableMatrixWithTieredPricingConfigTier) { } + + public ScalableMatrixWithTieredPricingConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithTieredPricingConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithTieredPricingConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.ScalableMatrixWithTieredPricingConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfigConverter) +)] +public record class NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionScalableMatrixWithTieredPricingPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/Cadence.cs deleted file mode 100644 index 1713faf0..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index cfbba907..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f9b4f13b..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionScalableMatrixWithTieredPricingPriceProperties = Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionScalableMatrixWithTieredPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ModelType.cs deleted file mode 100644 index 88f3e3ef..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithTieredPricingPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithTieredPricingPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithTieredPricing = new( - "scalable_matrix_with_tiered_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithTieredPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_tiered_pricing" => Value.ScalableMatrixWithTieredPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPrice.cs index b1f1d4c6..977579f0 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPrice.cs @@ -1,39 +1,37 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionScalableMatrixWithUnitPricingPriceProperties = Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionScalableMatrixWithUnitPricingPrice, + NewSubscriptionScalableMatrixWithUnitPricingPriceFromRaw + >) )] -public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionScalableMatrixWithUnitPricingPriceProperties::Cadence Cadence + public required ApiEnum< + string, + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence + > Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,35 +39,25 @@ public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionScalableMatrixWithUnitPricingPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum< + string, + NewSubscriptionScalableMatrixWithUnitPricingPriceModelType + > ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -77,47 +65,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary< - string, - Json::JsonElement - > ScalableMatrixWithUnitPricingConfig + /// + /// Configuration for scalable_matrix_with_unit_pricing pricing + /// + public required global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfig ScalableMatrixWithUnitPricingConfig { get { - if ( - !this.Properties.TryGetValue( - "scalable_matrix_with_unit_pricing_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "scalable_matrix_with_unit_pricing_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) - ?? throw new System::ArgumentNullException( - "scalable_matrix_with_unit_pricing_config" - ); - } - set - { - this.Properties["scalable_matrix_with_unit_pricing_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "scalable_matrix_with_unit_pricing_config" + ); } + init { JsonModel.Set(this._rawData, "scalable_matrix_with_unit_pricing_config", value); } } /// @@ -125,60 +89,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -186,83 +124,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -270,17 +173,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -288,19 +182,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -308,44 +191,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -353,16 +216,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -371,26 +234,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ScalableMatrixWithUnitPricingConfig.Values) - { - _ = item; - } + this.ScalableMatrixWithUnitPricingConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -402,32 +257,644 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionScalableMatrixWithUnitPricingPrice() { } + + public NewSubscriptionScalableMatrixWithUnitPricingPrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice newSubscriptionScalableMatrixWithUnitPricingPrice + ) + : base(newSubscriptionScalableMatrixWithUnitPricingPrice) { } + + public NewSubscriptionScalableMatrixWithUnitPricingPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionScalableMatrixWithUnitPricingPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionScalableMatrixWithUnitPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionScalableMatrixWithUnitPricingPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionScalableMatrixWithUnitPricingPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionScalableMatrixWithUnitPricingPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionScalableMatrixWithUnitPricingPriceCadenceConverter))] +public enum NewSubscriptionScalableMatrixWithUnitPricingPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionScalableMatrixWithUnitPricingPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionScalableMatrixWithUnitPricingPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual, + "semi_annual" => NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Monthly, + "quarterly" => NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Quarterly, + "one_time" => NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.OneTime, + "custom" => NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Custom, + _ => (NewSubscriptionScalableMatrixWithUnitPricingPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Annual => "annual", + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.SemiAnnual => + "semi_annual", + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Monthly => "monthly", + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Quarterly => "quarterly", + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.OneTime => "one_time", + NewSubscriptionScalableMatrixWithUnitPricingPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionScalableMatrixWithUnitPricingPriceModelTypeConverter))] +public enum NewSubscriptionScalableMatrixWithUnitPricingPriceModelType +{ + ScalableMatrixWithUnitPricing, +} + +sealed class NewSubscriptionScalableMatrixWithUnitPricingPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionScalableMatrixWithUnitPricingPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "scalable_matrix_with_unit_pricing" => + NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing, + _ => (NewSubscriptionScalableMatrixWithUnitPricingPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionScalableMatrixWithUnitPricingPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionScalableMatrixWithUnitPricingPriceModelType.ScalableMatrixWithUnitPricing => + "scalable_matrix_with_unit_pricing", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for scalable_matrix_with_unit_pricing pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfig, + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingConfig : JsonModel +{ + /// + /// Used to determine the unit rate + /// + public required string FirstDimension + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension"); } + init { JsonModel.Set(this._rawData, "first_dimension", value); } + } + + /// + /// Apply a scaling factor to each dimension + /// + public required IReadOnlyList MatrixScalingFactors + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "matrix_scaling_factors"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "matrix_scaling_factors", value); } } - public NewSubscriptionScalableMatrixWithUnitPricingPrice() { } + /// + /// The final unit price to rate against the output of the matrix + /// + public required string UnitPrice + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_price"); } + init { JsonModel.Set(this._rawData, "unit_price", value); } + } + + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + /// Used to determine the unit rate (optional) + /// + public string? SecondDimension + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension"); } + init { JsonModel.Set(this._rawData, "second_dimension", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimension; + foreach (var item in this.MatrixScalingFactors) + { + item.Validate(); + } + _ = this.UnitPrice; + _ = this.Prorate; + _ = this.SecondDimension; + } + + public ScalableMatrixWithUnitPricingConfig() { } + + public ScalableMatrixWithUnitPricingConfig( + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfig scalableMatrixWithUnitPricingConfig + ) + : base(scalableMatrixWithUnitPricingConfig) { } + + public ScalableMatrixWithUnitPricingConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionScalableMatrixWithUnitPricingPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single matrix scaling factor +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigMatrixScalingFactor, + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + >) +)] +public sealed record class ScalableMatrixWithUnitPricingConfigMatrixScalingFactor : JsonModel +{ + /// + /// First dimension value + /// + public required string FirstDimensionValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "first_dimension_value"); } + init { JsonModel.Set(this._rawData, "first_dimension_value", value); } + } + + /// + /// Scaling factor + /// + public required string ScalingFactor + { + get { return JsonModel.GetNotNullClass(this.RawData, "scaling_factor"); } + init { JsonModel.Set(this._rawData, "scaling_factor", value); } + } + + /// + /// Second dimension value (optional) + /// + public string? SecondDimensionValue + { + get { return JsonModel.GetNullableClass(this.RawData, "second_dimension_value"); } + init { JsonModel.Set(this._rawData, "second_dimension_value", value); } + } + + /// + public override void Validate() + { + _ = this.FirstDimensionValue; + _ = this.ScalingFactor; + _ = this.SecondDimensionValue; + } + + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor() { } + + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigMatrixScalingFactor scalableMatrixWithUnitPricingConfigMatrixScalingFactor + ) + : base(scalableMatrixWithUnitPricingConfigMatrixScalingFactor) { } + + public ScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ScalableMatrixWithUnitPricingConfigMatrixScalingFactor( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionScalableMatrixWithUnitPricingPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ScalableMatrixWithUnitPricingConfigMatrixScalingFactorFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigMatrixScalingFactor FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.ScalableMatrixWithUnitPricingConfigMatrixScalingFactor.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfigConverter) +)] +public record class NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionScalableMatrixWithUnitPricingPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/Cadence.cs deleted file mode 100644 index 1a4148f8..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 534e12b3..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index c355ccc0..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionScalableMatrixWithUnitPricingPriceProperties = Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionScalableMatrixWithUnitPricingPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ModelType.cs deleted file mode 100644 index 310ac50d..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionScalableMatrixWithUnitPricingPriceProperties/ModelType.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionScalableMatrixWithUnitPricingPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ScalableMatrixWithUnitPricing = new( - "scalable_matrix_with_unit_pricing" - ); - - readonly string _value = value; - - public enum Value - { - ScalableMatrixWithUnitPricing, - } - - public Value Known() => - _value switch - { - "scalable_matrix_with_unit_pricing" => Value.ScalableMatrixWithUnitPricing, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPrice.cs index ad58bd61..55c3c641 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPrice.cs @@ -1,39 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionThresholdTotalAmountPriceProperties = Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionThresholdTotalAmountPrice, + NewSubscriptionThresholdTotalAmountPriceFromRaw + >) )] -public sealed record class NewSubscriptionThresholdTotalAmountPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionThresholdTotalAmountPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionThresholdTotalAmountPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,35 +36,22 @@ public sealed record class NewSubscriptionThresholdTotalAmountPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionThresholdTotalAmountPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -77,41 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary ThresholdTotalAmountConfig + /// + /// Configuration for threshold_total_amount pricing + /// + public required global::Orb.Models.Subscriptions.ThresholdTotalAmountConfig ThresholdTotalAmountConfig { get { - if ( - !this.Properties.TryGetValue( - "threshold_total_amount_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "threshold_total_amount_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("threshold_total_amount_config"); - } - set - { - this.Properties["threshold_total_amount_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "threshold_total_amount_config" + ); } + init { JsonModel.Set(this._rawData, "threshold_total_amount_config", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionThresholdTotalAmountPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionThresholdTotalAmountPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.ThresholdTotalAmountConfig.Values) - { - _ = item; - } + this.ThresholdTotalAmountConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -396,32 +251,592 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionThresholdTotalAmountPrice() { } + + public NewSubscriptionThresholdTotalAmountPrice( + NewSubscriptionThresholdTotalAmountPrice newSubscriptionThresholdTotalAmountPrice + ) + : base(newSubscriptionThresholdTotalAmountPrice) { } + + public NewSubscriptionThresholdTotalAmountPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionThresholdTotalAmountPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionThresholdTotalAmountPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionThresholdTotalAmountPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionThresholdTotalAmountPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionThresholdTotalAmountPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionThresholdTotalAmountPriceCadenceConverter))] +public enum NewSubscriptionThresholdTotalAmountPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionThresholdTotalAmountPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionThresholdTotalAmountPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionThresholdTotalAmountPriceCadence.Annual, + "semi_annual" => NewSubscriptionThresholdTotalAmountPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionThresholdTotalAmountPriceCadence.Monthly, + "quarterly" => NewSubscriptionThresholdTotalAmountPriceCadence.Quarterly, + "one_time" => NewSubscriptionThresholdTotalAmountPriceCadence.OneTime, + "custom" => NewSubscriptionThresholdTotalAmountPriceCadence.Custom, + _ => (NewSubscriptionThresholdTotalAmountPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionThresholdTotalAmountPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionThresholdTotalAmountPriceCadence.Annual => "annual", + NewSubscriptionThresholdTotalAmountPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionThresholdTotalAmountPriceCadence.Monthly => "monthly", + NewSubscriptionThresholdTotalAmountPriceCadence.Quarterly => "quarterly", + NewSubscriptionThresholdTotalAmountPriceCadence.OneTime => "one_time", + NewSubscriptionThresholdTotalAmountPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionThresholdTotalAmountPriceModelTypeConverter))] +public enum NewSubscriptionThresholdTotalAmountPriceModelType +{ + ThresholdTotalAmount, +} + +sealed class NewSubscriptionThresholdTotalAmountPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionThresholdTotalAmountPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "threshold_total_amount" => + NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount, + _ => (NewSubscriptionThresholdTotalAmountPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionThresholdTotalAmountPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionThresholdTotalAmountPriceModelType.ThresholdTotalAmount => + "threshold_total_amount", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for threshold_total_amount pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ThresholdTotalAmountConfig, + global::Orb.Models.Subscriptions.ThresholdTotalAmountConfigFromRaw + >) +)] +public sealed record class ThresholdTotalAmountConfig : JsonModel +{ + /// + /// When the quantity consumed passes a provided threshold, the configured total + /// will be charged + /// + public required IReadOnlyList ConsumptionTable + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "consumption_table"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "consumption_table", value); } } - public NewSubscriptionThresholdTotalAmountPrice() { } + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init { JsonModel.Set(this._rawData, "prorate", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.ConsumptionTable) + { + item.Validate(); + } + _ = this.Prorate; + } + + public ThresholdTotalAmountConfig() { } + + public ThresholdTotalAmountConfig( + global::Orb.Models.Subscriptions.ThresholdTotalAmountConfig thresholdTotalAmountConfig + ) + : base(thresholdTotalAmountConfig) { } + + public ThresholdTotalAmountConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionThresholdTotalAmountPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + ThresholdTotalAmountConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.ThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ThresholdTotalAmountConfig( + List consumptionTable + ) + : this() + { + this.ConsumptionTable = consumptionTable; + } +} + +class ThresholdTotalAmountConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ThresholdTotalAmountConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.ThresholdTotalAmountConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single threshold +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.ConsumptionTable, + global::Orb.Models.Subscriptions.ConsumptionTableFromRaw + >) +)] +public sealed record class ConsumptionTable : JsonModel +{ + /// + /// Quantity threshold + /// + public required string Threshold + { + get { return JsonModel.GetNotNullClass(this.RawData, "threshold"); } + init { JsonModel.Set(this._rawData, "threshold", value); } + } + + /// + /// Total amount for this threshold + /// + public required string TotalAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "total_amount"); } + init { JsonModel.Set(this._rawData, "total_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Threshold; + _ = this.TotalAmount; + } + + public ConsumptionTable() { } + + public ConsumptionTable(global::Orb.Models.Subscriptions.ConsumptionTable consumptionTable) + : base(consumptionTable) { } + + public ConsumptionTable(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ConsumptionTable(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionThresholdTotalAmountPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.ConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ConsumptionTableFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.ConsumptionTable FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.ConsumptionTable.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSubscriptionThresholdTotalAmountPriceConversionRateConfigConverter))] +public record class NewSubscriptionThresholdTotalAmountPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionThresholdTotalAmountPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionThresholdTotalAmountPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionThresholdTotalAmountPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionThresholdTotalAmountPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionThresholdTotalAmountPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionThresholdTotalAmountPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionThresholdTotalAmountPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionThresholdTotalAmountPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionThresholdTotalAmountPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionThresholdTotalAmountPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionThresholdTotalAmountPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionThresholdTotalAmountPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionThresholdTotalAmountPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/Cadence.cs deleted file mode 100644 index c0df0953..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index bff6b250..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index aee5cb88..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionThresholdTotalAmountPriceProperties = Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionThresholdTotalAmountPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionThresholdTotalAmountPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ModelType.cs deleted file mode 100644 index d4e8482d..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionThresholdTotalAmountPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionThresholdTotalAmountPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType ThresholdTotalAmount = new("threshold_total_amount"); - - readonly string _value = value; - - public enum Value - { - ThresholdTotalAmount, - } - - public Value Known() => - _value switch - { - "threshold_total_amount" => Value.ThresholdTotalAmount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPrice.cs deleted file mode 100644 index ea525a59..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPrice.cs +++ /dev/null @@ -1,423 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionTierWithProrationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionTierWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The cadence to bill for this price on. - /// - public required NewSubscriptionTierWithProrationPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewSubscriptionTierWithProrationPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::Dictionary TieredWithProrationConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "tiered_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_proration_config"); - } - set - { - this.Properties["tiered_with_proration_config"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewSubscriptionTierWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - foreach (var item in this.TieredWithProrationConfig.Values) - { - _ = item; - } - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewSubscriptionTierWithProrationPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionTierWithProrationPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewSubscriptionTierWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index 9f36ac97..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index fb1cf4ac..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 685a8aa0..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionTierWithProrationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionTierWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionTierWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index 0e52cad6..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTierWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTierWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithProration = new("tiered_with_proration"); - - readonly string _value = value; - - public enum Value - { - TieredWithProration, - } - - public Value Known() => - _value switch - { - "tiered_with_proration" => Value.TieredWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPrice.cs deleted file mode 100644 index 929dd8d4..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPrice.cs +++ /dev/null @@ -1,413 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionTieredBPSPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionTieredBPSPrice - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The cadence to bill for this price on. - /// - public required NewSubscriptionTieredBPSPriceProperties::Cadence Cadence - { - get - { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); - } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the item the price will be associated with. - /// - public required string ItemID - { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required NewSubscriptionTieredBPSPriceProperties::ModelType ModelType - { - get - { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); - } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The name of the price. - /// - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::TieredBPSConfig TieredBPSConfig - { - get - { - if (!this.Properties.TryGetValue("tiered_bps_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_bps_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_bps_config"); - } - set - { - this.Properties["tiered_bps_config"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the billable metric for the price. Only needed if the price is usage-based. - /// - public string? BillableMetricID - { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. - /// - public bool? BilledInAdvance - { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// For custom cadence: specifies the duration of the billing period in days or months. - /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The per unit conversion rate of the price currency to the invoicing currency. - /// - public double? ConversionRate - { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The configuration for the rate of the price currency to the invoicing currency. - /// - public NewSubscriptionTieredBPSPriceProperties::ConversionRateConfig? ConversionRateConfig - { - get - { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. - /// - public string? Currency - { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// For dimensional price: specifies a price group and dimension values - /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An alias for the price. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// If the Price represents a fixed cost, this represents the quantity of units applied. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The property used to group this price on an invoice - /// - public string? InvoiceGroupingKey - { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// Within each billing cycle, specifies the cadence at which invoices are produced. - /// If unspecified, a single invoice is produced per billing cycle. - /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration - { - get - { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// User-specified key/value pairs for the resource. Individual keys can be removed - /// by setting the value to `null`, and the entire metadata mapping can be cleared - /// by setting `metadata` to `null`. - /// - public Generic::Dictionary? Metadata - { - get - { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A transient ID that can be used to reference this price when adding adjustments - /// in the same API call. - /// - public string? ReferenceID - { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Cadence.Validate(); - _ = this.ItemID; - this.ModelType.Validate(); - _ = this.Name; - this.TieredBPSConfig.Validate(); - _ = this.BillableMetricID; - _ = this.BilledInAdvance; - this.BillingCycleConfiguration?.Validate(); - _ = this.ConversionRate; - this.ConversionRateConfig?.Validate(); - _ = this.Currency; - this.DimensionalPriceConfiguration?.Validate(); - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.InvoiceGroupingKey; - this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } - _ = this.ReferenceID; - } - - public NewSubscriptionTieredBPSPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionTieredBPSPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static NewSubscriptionTieredBPSPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/Cadence.cs deleted file mode 100644 index e1bf8e0f..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 016cf917..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index dc995afb..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionTieredBPSPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionTieredBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionTieredBPSPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ModelType.cs deleted file mode 100644 index 015f750e..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredBPSPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredBPSPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredBPS = new("tiered_bps"); - - readonly string _value = value; - - public enum Value - { - TieredBPS, - } - - public Value Known() => - _value switch - { - "tiered_bps" => Value.TieredBPS, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePrice.cs index f2fc38eb..af081dfe 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePrice.cs @@ -1,37 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionTieredPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionTieredPackagePrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionTieredPackagePrice, + NewSubscriptionTieredPackagePriceFromRaw + >) +)] +public sealed record class NewSubscriptionTieredPackagePrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionTieredPackagePriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +36,22 @@ public sealed record class NewSubscriptionTieredPackagePrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionTieredPackagePriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,39 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredPackageConfig + /// + /// Configuration for tiered_package pricing + /// + public required global::Orb.Models.Subscriptions.TieredPackageConfig TieredPackageConfig { get { - if ( - !this.Properties.TryGetValue("tiered_package_config", out Json::JsonElement element) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_config"); - } - set - { - this.Properties["tiered_package_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_config" ); } + init { JsonModel.Set(this._rawData, "tiered_package_config", value); } } /// @@ -115,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -176,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionTieredPackagePriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionTieredPackagePriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -260,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -278,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -298,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -343,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -361,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredPackageConfig.Values) - { - _ = item; - } + this.TieredPackageConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -392,30 +251,583 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionTieredPackagePrice() { } + public NewSubscriptionTieredPackagePrice( + NewSubscriptionTieredPackagePrice newSubscriptionTieredPackagePrice + ) + : base(newSubscriptionTieredPackagePrice) { } + + public NewSubscriptionTieredPackagePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionTieredPackagePrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionTieredPackagePrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionTieredPackagePrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionTieredPackagePriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionTieredPackagePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionTieredPackagePrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionTieredPackagePriceCadenceConverter))] +public enum NewSubscriptionTieredPackagePriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionTieredPackagePriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionTieredPackagePriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionTieredPackagePriceCadence.Annual, + "semi_annual" => NewSubscriptionTieredPackagePriceCadence.SemiAnnual, + "monthly" => NewSubscriptionTieredPackagePriceCadence.Monthly, + "quarterly" => NewSubscriptionTieredPackagePriceCadence.Quarterly, + "one_time" => NewSubscriptionTieredPackagePriceCadence.OneTime, + "custom" => NewSubscriptionTieredPackagePriceCadence.Custom, + _ => (NewSubscriptionTieredPackagePriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPackagePriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionTieredPackagePriceCadence.Annual => "annual", + NewSubscriptionTieredPackagePriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionTieredPackagePriceCadence.Monthly => "monthly", + NewSubscriptionTieredPackagePriceCadence.Quarterly => "quarterly", + NewSubscriptionTieredPackagePriceCadence.OneTime => "one_time", + NewSubscriptionTieredPackagePriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionTieredPackagePriceModelTypeConverter))] +public enum NewSubscriptionTieredPackagePriceModelType +{ + TieredPackage, +} + +sealed class NewSubscriptionTieredPackagePriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionTieredPackagePriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_package" => NewSubscriptionTieredPackagePriceModelType.TieredPackage, + _ => (NewSubscriptionTieredPackagePriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPackagePriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionTieredPackagePriceModelType.TieredPackage => "tiered_package", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredPackageConfig, + global::Orb.Models.Subscriptions.TieredPackageConfigFromRaw + >) +)] +public sealed record class TieredPackageConfig : JsonModel +{ + /// + /// Package size + /// + public required string PackageSize + { + get { return JsonModel.GetNotNullClass(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. The tier bounds are defined + /// based on the total quantity rather than the number of packages, so they must + /// be multiples of the package size. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredPackageConfig() { } + + public TieredPackageConfig( + global::Orb.Models.Subscriptions.TieredPackageConfig tieredPackageConfig + ) + : base(tieredPackageConfig) { } + + public TieredPackageConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredPackageConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredPackageConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier with business logic +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredPackageConfigTier, + global::Orb.Models.Subscriptions.TieredPackageConfigTierFromRaw + >) +)] +public sealed record class TieredPackageConfigTier : JsonModel +{ + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public TieredPackageConfigTier() { } + + public TieredPackageConfigTier( + global::Orb.Models.Subscriptions.TieredPackageConfigTier tieredPackageConfigTier + ) + : base(tieredPackageConfigTier) { } + + public TieredPackageConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredPackageConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredPackageConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSubscriptionTieredPackagePriceConversionRateConfigConverter))] +public record class NewSubscriptionTieredPackagePriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredPackagePriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPackagePriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPackagePriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionTieredPackagePriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionTieredPackagePriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPackagePriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionTieredPackagePriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionTieredPackagePriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionTieredPackagePriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionTieredPackagePriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPackagePriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/Cadence.cs deleted file mode 100644 index c58e260c..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 39d9c9d5..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index b833e65c..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionTieredPackagePriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionTieredPackagePriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ModelType.cs deleted file mode 100644 index 22eb396a..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackagePriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackagePriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackage = new("tiered_package"); - - readonly string _value = value; - - public enum Value - { - TieredPackage, - } - - public Value Known() => - _value switch - { - "tiered_package" => Value.TieredPackage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPrice.cs index 5516e03c..a752b3e4 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPrice.cs @@ -1,39 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionTieredPackageWithMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter( - typeof(Orb::ModelConverter) +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionTieredPackageWithMinimumPrice, + NewSubscriptionTieredPackageWithMinimumPriceFromRaw + >) )] -public sealed record class NewSubscriptionTieredPackageWithMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +public sealed record class NewSubscriptionTieredPackageWithMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionTieredPackageWithMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -41,35 +36,22 @@ public sealed record class NewSubscriptionTieredPackageWithMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionTieredPackageWithMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -77,41 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredPackageWithMinimumConfig + /// + /// Configuration for tiered_package_with_minimum pricing + /// + public required global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfig TieredPackageWithMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_package_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_package_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_package_with_minimum_config"); - } - set - { - this.Properties["tiered_package_with_minimum_config"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_package_with_minimum_config" + ); } + init { JsonModel.Set(this._rawData, "tiered_package_with_minimum_config", value); } } /// @@ -119,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -180,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionTieredPackageWithMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -264,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -282,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -302,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -347,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -365,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredPackageWithMinimumConfig.Values) - { - _ = item; - } + this.TieredPackageWithMinimumConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -396,32 +251,603 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionTieredPackageWithMinimumPrice() { } + + public NewSubscriptionTieredPackageWithMinimumPrice( + NewSubscriptionTieredPackageWithMinimumPrice newSubscriptionTieredPackageWithMinimumPrice + ) + : base(newSubscriptionTieredPackageWithMinimumPrice) { } + + public NewSubscriptionTieredPackageWithMinimumPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionTieredPackageWithMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionTieredPackageWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionTieredPackageWithMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionTieredPackageWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionTieredPackageWithMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionTieredPackageWithMinimumPriceCadenceConverter))] +public enum NewSubscriptionTieredPackageWithMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionTieredPackageWithMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionTieredPackageWithMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual, + "semi_annual" => NewSubscriptionTieredPackageWithMinimumPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionTieredPackageWithMinimumPriceCadence.Monthly, + "quarterly" => NewSubscriptionTieredPackageWithMinimumPriceCadence.Quarterly, + "one_time" => NewSubscriptionTieredPackageWithMinimumPriceCadence.OneTime, + "custom" => NewSubscriptionTieredPackageWithMinimumPriceCadence.Custom, + _ => (NewSubscriptionTieredPackageWithMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPackageWithMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; - } + NewSubscriptionTieredPackageWithMinimumPriceCadence.Annual => "annual", + NewSubscriptionTieredPackageWithMinimumPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionTieredPackageWithMinimumPriceCadence.Monthly => "monthly", + NewSubscriptionTieredPackageWithMinimumPriceCadence.Quarterly => "quarterly", + NewSubscriptionTieredPackageWithMinimumPriceCadence.OneTime => "one_time", + NewSubscriptionTieredPackageWithMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionTieredPackageWithMinimumPriceModelTypeConverter))] +public enum NewSubscriptionTieredPackageWithMinimumPriceModelType +{ + TieredPackageWithMinimum, +} + +sealed class NewSubscriptionTieredPackageWithMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionTieredPackageWithMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_package_with_minimum" => + NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum, + _ => (NewSubscriptionTieredPackageWithMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPackageWithMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionTieredPackageWithMinimumPriceModelType.TieredPackageWithMinimum => + "tiered_package_with_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_package_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfig, + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumConfig : JsonModel +{ + /// + /// Package size + /// + public required double PackageSize + { + get { return JsonModel.GetNotNullStruct(this.RawData, "package_size"); } + init { JsonModel.Set(this._rawData, "package_size", value); } + } + + /// + /// Apply tiered pricing after rounding up the quantity to the package size. + /// Tiers are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); } - _ = this.ReferenceID; + init { JsonModel.Set(this._rawData, "tiers", value); } } - public NewSubscriptionTieredPackageWithMinimumPrice() { } + /// + public override void Validate() + { + _ = this.PackageSize; + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredPackageWithMinimumConfig() { } + + public TieredPackageWithMinimumConfig( + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfig tieredPackageWithMinimumConfig + ) + : base(tieredPackageWithMinimumConfig) { } + + public TieredPackageWithMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionTieredPackageWithMinimumPrice( - Generic::Dictionary properties + [SetsRequiredMembers] + TieredPackageWithMinimumConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData ) { - Properties = properties; + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigTier, + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigTierFromRaw + >) +)] +public sealed record class TieredPackageWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Price per package + /// + public required string PerUnit + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit"); } + init { JsonModel.Set(this._rawData, "per_unit", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.PerUnit; + _ = this.TierLowerBound; + } + + public TieredPackageWithMinimumConfigTier() { } + + public TieredPackageWithMinimumConfigTier( + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigTier tieredPackageWithMinimumConfigTier + ) + : base(tieredPackageWithMinimumConfigTier) { } + + public TieredPackageWithMinimumConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredPackageWithMinimumConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionTieredPackageWithMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredPackageWithMinimumConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.TieredPackageWithMinimumConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfigConverter))] +public record class NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPackageWithMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 0b425ed6..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 2e4adcaf..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index f1767754..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionTieredPackageWithMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionTieredPackageWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionTieredPackageWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ModelType.cs deleted file mode 100644 index 469b1d6b..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPackageWithMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPackageWithMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredPackageWithMinimum = new("tiered_package_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredPackageWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_package_with_minimum" => Value.TieredPackageWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPrice.cs index 7d1ecd1e..5da43584 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPrice.cs @@ -1,37 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionTieredPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionTieredPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewSubscriptionTieredPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionTieredPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +34,23 @@ public sealed record class NewSubscriptionTieredPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionTieredPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,31 +58,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Models::TieredConfig TieredConfig + /// + /// Configuration for tiered pricing + /// + public required TieredConfig TieredConfig { - get - { - if (!this.Properties.TryGetValue("tiered_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_config"); - } - set { this.Properties["tiered_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "tiered_config"); } + init { JsonModel.Set(this._rawData, "tiered_config", value); } } /// @@ -107,60 +76,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -168,83 +111,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionTieredPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionTieredPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +160,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +169,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,44 +178,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,16 +203,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -353,16 +221,11 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -381,30 +244,422 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionTieredPrice() { } + public NewSubscriptionTieredPrice(NewSubscriptionTieredPrice newSubscriptionTieredPrice) + : base(newSubscriptionTieredPrice) { } + + public NewSubscriptionTieredPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionTieredPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionTieredPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionTieredPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionTieredPriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionTieredPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionTieredPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionTieredPriceCadenceConverter))] +public enum NewSubscriptionTieredPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionTieredPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionTieredPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionTieredPriceCadence.Annual, + "semi_annual" => NewSubscriptionTieredPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionTieredPriceCadence.Monthly, + "quarterly" => NewSubscriptionTieredPriceCadence.Quarterly, + "one_time" => NewSubscriptionTieredPriceCadence.OneTime, + "custom" => NewSubscriptionTieredPriceCadence.Custom, + _ => (NewSubscriptionTieredPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionTieredPriceCadence.Annual => "annual", + NewSubscriptionTieredPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionTieredPriceCadence.Monthly => "monthly", + NewSubscriptionTieredPriceCadence.Quarterly => "quarterly", + NewSubscriptionTieredPriceCadence.OneTime => "one_time", + NewSubscriptionTieredPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionTieredPriceModelTypeConverter))] +public enum NewSubscriptionTieredPriceModelType +{ + Tiered, +} + +sealed class NewSubscriptionTieredPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionTieredPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered" => NewSubscriptionTieredPriceModelType.Tiered, + _ => (NewSubscriptionTieredPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionTieredPriceModelType.Tiered => "tiered", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionTieredPriceConversionRateConfigConverter))] +public record class NewSubscriptionTieredPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionTieredPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionTieredPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionTieredPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionTieredPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionTieredPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionTieredPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/Cadence.cs deleted file mode 100644 index 122abf01..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 739ecfca..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 96bc1ec1..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionTieredPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionTieredPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ModelType.cs deleted file mode 100644 index 3704e42c..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Tiered = new("tiered"); - - readonly string _value = value; - - public enum Value - { - Tiered, - } - - public Value Known() => - _value switch - { - "tiered" => Value.Tiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPrice.cs index 9d4ec07b..6f55693c 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPrice.cs @@ -1,37 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionTieredWithMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionTieredWithMinimumPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionTieredWithMinimumPrice, + NewSubscriptionTieredWithMinimumPriceFromRaw + >) +)] +public sealed record class NewSubscriptionTieredWithMinimumPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionTieredWithMinimumPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +36,22 @@ public sealed record class NewSubscriptionTieredWithMinimumPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionTieredWithMinimumPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,42 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary TieredWithMinimumConfig + /// + /// Configuration for tiered_with_minimum pricing + /// + public required global::Orb.Models.Subscriptions.TieredWithMinimumConfig TieredWithMinimumConfig { get { - if ( - !this.Properties.TryGetValue( - "tiered_with_minimum_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "tiered_with_minimum_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("tiered_with_minimum_config"); - } - set - { - this.Properties["tiered_with_minimum_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_minimum_config" ); } + init { JsonModel.Set(this._rawData, "tiered_with_minimum_config", value); } } /// @@ -118,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -179,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionTieredWithMinimumPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionTieredWithMinimumPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -364,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.TieredWithMinimumConfig.Values) - { - _ = item; - } + this.TieredWithMinimumConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -395,30 +251,629 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) + _ = this.Metadata; + _ = this.ReferenceID; + } + + public NewSubscriptionTieredWithMinimumPrice() { } + + public NewSubscriptionTieredWithMinimumPrice( + NewSubscriptionTieredWithMinimumPrice newSubscriptionTieredWithMinimumPrice + ) + : base(newSubscriptionTieredWithMinimumPrice) { } + + public NewSubscriptionTieredWithMinimumPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + NewSubscriptionTieredWithMinimumPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static NewSubscriptionTieredWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionTieredWithMinimumPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionTieredWithMinimumPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionTieredWithMinimumPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionTieredWithMinimumPriceCadenceConverter))] +public enum NewSubscriptionTieredWithMinimumPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionTieredWithMinimumPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionTieredWithMinimumPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - foreach (var item in this.Metadata.Values) + "annual" => NewSubscriptionTieredWithMinimumPriceCadence.Annual, + "semi_annual" => NewSubscriptionTieredWithMinimumPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionTieredWithMinimumPriceCadence.Monthly, + "quarterly" => NewSubscriptionTieredWithMinimumPriceCadence.Quarterly, + "one_time" => NewSubscriptionTieredWithMinimumPriceCadence.OneTime, + "custom" => NewSubscriptionTieredWithMinimumPriceCadence.Custom, + _ => (NewSubscriptionTieredWithMinimumPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredWithMinimumPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch { - _ = item; + NewSubscriptionTieredWithMinimumPriceCadence.Annual => "annual", + NewSubscriptionTieredWithMinimumPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionTieredWithMinimumPriceCadence.Monthly => "monthly", + NewSubscriptionTieredWithMinimumPriceCadence.Quarterly => "quarterly", + NewSubscriptionTieredWithMinimumPriceCadence.OneTime => "one_time", + NewSubscriptionTieredWithMinimumPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionTieredWithMinimumPriceModelTypeConverter))] +public enum NewSubscriptionTieredWithMinimumPriceModelType +{ + TieredWithMinimum, +} + +sealed class NewSubscriptionTieredWithMinimumPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionTieredWithMinimumPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tiered_with_minimum" => + NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum, + _ => (NewSubscriptionTieredWithMinimumPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredWithMinimumPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionTieredWithMinimumPriceModelType.TieredWithMinimum => + "tiered_with_minimum", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_minimum pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredWithMinimumConfig, + global::Orb.Models.Subscriptions.TieredWithMinimumConfigFromRaw + >) +)] +public sealed record class TieredWithMinimumConfig : JsonModel +{ + /// + /// Tiered pricing with a minimum amount dependent on the volume tier. Tiers + /// are defined using exclusive lower bounds. + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// If true, tiers with an accrued amount of 0 will not be included in the rating. + /// + public bool? HideZeroAmountTiers + { + get { return JsonModel.GetNullableStruct(this.RawData, "hide_zero_amount_tiers"); } + init + { + if (value == null) + { + return; } + + JsonModel.Set(this._rawData, "hide_zero_amount_tiers", value); } - _ = this.ReferenceID; } - public NewSubscriptionTieredWithMinimumPrice() { } + /// + /// If true, the unit price will be prorated to the billing period + /// + public bool? Prorate + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorate"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorate", value); + } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + _ = this.HideZeroAmountTiers; + _ = this.Prorate; + } + + public TieredWithMinimumConfig() { } + + public TieredWithMinimumConfig( + global::Orb.Models.Subscriptions.TieredWithMinimumConfig tieredWithMinimumConfig + ) + : base(tieredWithMinimumConfig) { } + + public TieredWithMinimumConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionTieredWithMinimumPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + TieredWithMinimumConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static NewSubscriptionTieredWithMinimumPrice FromRawUnchecked( - Generic::Dictionary properties + /// + public static global::Orb.Models.Subscriptions.TieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithMinimumConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithMinimumConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredWithMinimumConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredWithMinimumConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredWithMinimumConfigTier, + global::Orb.Models.Subscriptions.TieredWithMinimumConfigTierFromRaw + >) +)] +public sealed record class TieredWithMinimumConfigTier : JsonModel +{ + /// + /// Minimum amount + /// + public required string MinimumAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// Tier lower bound + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Per unit amount + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.MinimumAmount; + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithMinimumConfigTier() { } + + public TieredWithMinimumConfigTier( + global::Orb.Models.Subscriptions.TieredWithMinimumConfigTier tieredWithMinimumConfigTier + ) + : base(tieredWithMinimumConfigTier) { } + + public TieredWithMinimumConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithMinimumConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithMinimumConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredWithMinimumConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredWithMinimumConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSubscriptionTieredWithMinimumPriceConversionRateConfigConverter))] +public record class NewSubscriptionTieredWithMinimumPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionTieredWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionTieredWithMinimumPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredWithMinimumPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredWithMinimumPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionTieredWithMinimumPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionTieredWithMinimumPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionTieredWithMinimumPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionTieredWithMinimumPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionTieredWithMinimumPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionTieredWithMinimumPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionTieredWithMinimumPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionTieredWithMinimumPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/Cadence.cs deleted file mode 100644 index 31240a62..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index c577c27a..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 81308c45..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionTieredWithMinimumPriceProperties = Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionTieredWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionTieredWithMinimumPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ModelType.cs deleted file mode 100644 index 1ec48f93..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionTieredWithMinimumPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionTieredWithMinimumPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType TieredWithMinimum = new("tiered_with_minimum"); - - readonly string _value = value; - - public enum Value - { - TieredWithMinimum, - } - - public Value Known() => - _value switch - { - "tiered_with_minimum" => Value.TieredWithMinimum, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitPrice.cs index a33055de..167693a1 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionUnitPrice.cs @@ -1,37 +1,32 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionUnitPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionUnitPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class NewSubscriptionUnitPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionUnitPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +34,23 @@ public sealed record class NewSubscriptionUnitPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionUnitPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "model_type" + ); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,31 +58,17 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Models::UnitConfig UnitConfig + /// + /// Configuration for unit pricing + /// + public required UnitConfig UnitConfig { - get - { - if (!this.Properties.TryGetValue("unit_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_config"); - } - set { this.Properties["unit_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "unit_config"); } + init { JsonModel.Set(this._rawData, "unit_config", value); } } /// @@ -107,60 +76,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -168,83 +111,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionUnitPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionUnitPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -252,17 +160,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -270,19 +169,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -290,44 +178,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -335,16 +203,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -353,16 +221,11 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); @@ -381,30 +244,422 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionUnitPrice() { } + public NewSubscriptionUnitPrice(NewSubscriptionUnitPrice newSubscriptionUnitPrice) + : base(newSubscriptionUnitPrice) { } + + public NewSubscriptionUnitPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionUnitPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionUnitPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionUnitPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionUnitPriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionUnitPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionUnitPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionUnitPriceCadenceConverter))] +public enum NewSubscriptionUnitPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionUnitPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionUnitPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionUnitPriceCadence.Annual, + "semi_annual" => NewSubscriptionUnitPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionUnitPriceCadence.Monthly, + "quarterly" => NewSubscriptionUnitPriceCadence.Quarterly, + "one_time" => NewSubscriptionUnitPriceCadence.OneTime, + "custom" => NewSubscriptionUnitPriceCadence.Custom, + _ => (NewSubscriptionUnitPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionUnitPriceCadence.Annual => "annual", + NewSubscriptionUnitPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionUnitPriceCadence.Monthly => "monthly", + NewSubscriptionUnitPriceCadence.Quarterly => "quarterly", + NewSubscriptionUnitPriceCadence.OneTime => "one_time", + NewSubscriptionUnitPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionUnitPriceModelTypeConverter))] +public enum NewSubscriptionUnitPriceModelType +{ + Unit, +} + +sealed class NewSubscriptionUnitPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionUnitPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit" => NewSubscriptionUnitPriceModelType.Unit, + _ => (NewSubscriptionUnitPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionUnitPriceModelType.Unit => "unit", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(NewSubscriptionUnitPriceConversionRateConfigConverter))] +public record class NewSubscriptionUnitPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionUnitPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionUnitPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionUnitPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionUnitPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionUnitPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionUnitPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionUnitPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionUnitPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionUnitPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/Cadence.cs deleted file mode 100644 index 770fab2c..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 9a11e27c..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 3fb69ee2..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionUnitPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionUnitPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionUnitPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ModelType.cs deleted file mode 100644 index 1d27ee47..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType Unit = new("unit"); - - readonly string _value = value; - - public enum Value - { - Unit, - } - - public Value Known() => - _value switch - { - "unit" => Value.Unit, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPrice.cs index ae159885..e45c9139 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPrice.cs @@ -1,37 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionUnitWithPercentPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionUnitWithPercentPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionUnitWithPercentPrice, + NewSubscriptionUnitWithPercentPriceFromRaw + >) +)] +public sealed record class NewSubscriptionUnitWithPercentPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionUnitWithPercentPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +36,22 @@ public sealed record class NewSubscriptionUnitWithPercentPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionUnitWithPercentPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,42 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary UnitWithPercentConfig + /// + /// Configuration for unit_with_percent pricing + /// + public required global::Orb.Models.Subscriptions.UnitWithPercentConfig UnitWithPercentConfig { get { - if ( - !this.Properties.TryGetValue( - "unit_with_percent_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_percent_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_percent_config"); - } - set - { - this.Properties["unit_with_percent_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_percent_config" ); } + init { JsonModel.Set(this._rawData, "unit_with_percent_config", value); } } /// @@ -118,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -179,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionUnitWithPercentPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionUnitWithPercentPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -364,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.UnitWithPercentConfig.Values) - { - _ = item; - } + this.UnitWithPercentConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -395,30 +251,498 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionUnitWithPercentPrice() { } + public NewSubscriptionUnitWithPercentPrice( + NewSubscriptionUnitWithPercentPrice newSubscriptionUnitWithPercentPrice + ) + : base(newSubscriptionUnitWithPercentPrice) { } + + public NewSubscriptionUnitWithPercentPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionUnitWithPercentPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionUnitWithPercentPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionUnitWithPercentPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionUnitWithPercentPriceFromRaw : IFromRawJson +{ + /// + public NewSubscriptionUnitWithPercentPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionUnitWithPercentPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionUnitWithPercentPriceCadenceConverter))] +public enum NewSubscriptionUnitWithPercentPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionUnitWithPercentPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionUnitWithPercentPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionUnitWithPercentPriceCadence.Annual, + "semi_annual" => NewSubscriptionUnitWithPercentPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionUnitWithPercentPriceCadence.Monthly, + "quarterly" => NewSubscriptionUnitWithPercentPriceCadence.Quarterly, + "one_time" => NewSubscriptionUnitWithPercentPriceCadence.OneTime, + "custom" => NewSubscriptionUnitWithPercentPriceCadence.Custom, + _ => (NewSubscriptionUnitWithPercentPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitWithPercentPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionUnitWithPercentPriceCadence.Annual => "annual", + NewSubscriptionUnitWithPercentPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionUnitWithPercentPriceCadence.Monthly => "monthly", + NewSubscriptionUnitWithPercentPriceCadence.Quarterly => "quarterly", + NewSubscriptionUnitWithPercentPriceCadence.OneTime => "one_time", + NewSubscriptionUnitWithPercentPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionUnitWithPercentPriceModelTypeConverter))] +public enum NewSubscriptionUnitWithPercentPriceModelType +{ + UnitWithPercent, +} + +sealed class NewSubscriptionUnitWithPercentPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionUnitWithPercentPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit_with_percent" => NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent, + _ => (NewSubscriptionUnitWithPercentPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitWithPercentPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionUnitWithPercentPriceModelType.UnitWithPercent => "unit_with_percent", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.UnitWithPercentConfig, + global::Orb.Models.Subscriptions.UnitWithPercentConfigFromRaw + >) +)] +public sealed record class UnitWithPercentConfig : JsonModel +{ + /// + /// What percent, out of 100, of the calculated total to charge + /// + public required string Percent + { + get { return JsonModel.GetNotNullClass(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + _ = this.UnitAmount; + } + + public UnitWithPercentConfig() { } + + public UnitWithPercentConfig( + global::Orb.Models.Subscriptions.UnitWithPercentConfig unitWithPercentConfig + ) + : base(unitWithPercentConfig) { } + + public UnitWithPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.UnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UnitWithPercentConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.UnitWithPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.UnitWithPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSubscriptionUnitWithPercentPriceConversionRateConfigConverter))] +public record class NewSubscriptionUnitWithPercentPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionUnitWithPercentPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionUnitWithPercentPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionUnitWithPercentPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitWithPercentPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitWithPercentPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionUnitWithPercentPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionUnitWithPercentPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitWithPercentPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionUnitWithPercentPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionUnitWithPercentPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionUnitWithPercentPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionUnitWithPercentPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitWithPercentPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/Cadence.cs deleted file mode 100644 index dd13036f..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index 24fd5ef9..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index bb15196d..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionUnitWithPercentPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionUnitWithPercentPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionUnitWithPercentPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ModelType.cs deleted file mode 100644 index 3dd5479f..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithPercentPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithPercentPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithPercent = new("unit_with_percent"); - - readonly string _value = value; - - public enum Value - { - UnitWithPercent, - } - - public Value Known() => - _value switch - { - "unit_with_percent" => Value.UnitWithPercent, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPrice.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPrice.cs index ed368e39..2e32024b 100644 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPrice.cs +++ b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPrice.cs @@ -1,37 +1,34 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using NewSubscriptionUnitWithProrationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class NewSubscriptionUnitWithProrationPrice - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + NewSubscriptionUnitWithProrationPrice, + NewSubscriptionUnitWithProrationPriceFromRaw + >) +)] +public sealed record class NewSubscriptionUnitWithProrationPrice : JsonModel { /// /// The cadence to bill for this price on. /// - public required NewSubscriptionUnitWithProrationPriceProperties::Cadence Cadence + public required ApiEnum Cadence { get { - if (!this.Properties.TryGetValue("cadence", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cadence", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cadence"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); } - set { this.Properties["cadence"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "cadence", value); } } /// @@ -39,35 +36,22 @@ public sealed record class NewSubscriptionUnitWithProrationPrice /// public required string ItemID { - get - { - if (!this.Properties.TryGetValue("item_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "item_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("item_id"); - } - set { this.Properties["item_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } } - public required NewSubscriptionUnitWithProrationPriceProperties::ModelType ModelType + /// + /// The pricing model type + /// + public required ApiEnum ModelType { get { - if (!this.Properties.TryGetValue("model_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "model_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("model_type"); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "model_type"); } - set { this.Properties["model_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "model_type", value); } } /// @@ -75,42 +59,23 @@ public required string ItemID /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } - public required Generic::Dictionary UnitWithProrationConfig + /// + /// Configuration for unit_with_proration pricing + /// + public required global::Orb.Models.Subscriptions.UnitWithProrationConfig UnitWithProrationConfig { get { - if ( - !this.Properties.TryGetValue( - "unit_with_proration_config", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "unit_with_proration_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("unit_with_proration_config"); - } - set - { - this.Properties["unit_with_proration_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "unit_with_proration_config" ); } + init { JsonModel.Set(this._rawData, "unit_with_proration_config", value); } } /// @@ -118,60 +83,34 @@ public required string Name /// public string? BillableMetricID { - get - { - if (!this.Properties.TryGetValue("billable_metric_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } } /// - /// If the Price represents a fixed cost, the price will be billed in-advance if - /// this is true, and in-arrears if this is false. + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. /// public bool? BilledInAdvance { - get - { - if (!this.Properties.TryGetValue("billed_in_advance", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billed_in_advance"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } } /// - /// For custom cadence: specifies the duration of the billing period in days or months. + /// For custom cadence: specifies the duration of the billing period in days + /// or months. /// - public Models::NewBillingCycleConfiguration? BillingCycleConfiguration + public NewBillingCycleConfiguration? BillingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } } /// @@ -179,83 +118,48 @@ public bool? BilledInAdvance /// public double? ConversionRate { - get - { - if (!this.Properties.TryGetValue("conversion_rate", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["conversion_rate"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } } /// /// The configuration for the rate of the price currency to the invoicing currency. /// - public NewSubscriptionUnitWithProrationPriceProperties::ConversionRateConfig? ConversionRateConfig + public NewSubscriptionUnitWithProrationPriceConversionRateConfig? ConversionRateConfig { get { - if ( - !this.Properties.TryGetValue( - "conversion_rate_config", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.Properties["conversion_rate_config"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" ); } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } } /// - /// An ISO 4217 currency string, or custom pricing unit identifier, in which this - /// price is billed. + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. /// public string? Currency { - get - { - if (!this.Properties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } } /// /// For dimensional price: specifies a price group and dimension values /// - public Models::NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration { get { - if ( - !this.Properties.TryGetValue( - "dimensional_price_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" ); } - set - { - this.Properties["dimensional_price_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } } /// @@ -263,17 +167,8 @@ public string? Currency /// public string? ExternalPriceID { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } } /// @@ -281,19 +176,8 @@ public string? ExternalPriceID /// public double? FixedPriceQuantity { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } } /// @@ -301,44 +185,24 @@ public double? FixedPriceQuantity /// public string? InvoiceGroupingKey { - get - { - if (!this.Properties.TryGetValue("invoice_grouping_key", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoice_grouping_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } } /// /// Within each billing cycle, specifies the cadence at which invoices are produced. /// If unspecified, a single invoice is produced per billing cycle. /// - public Models::NewBillingCycleConfiguration? InvoicingCycleConfiguration + public NewBillingCycleConfiguration? InvoicingCycleConfiguration { get { - if ( - !this.Properties.TryGetValue( - "invoicing_cycle_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_cycle_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } } /// @@ -346,16 +210,16 @@ public string? InvoiceGroupingKey /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// @@ -364,26 +228,18 @@ public string? InvoiceGroupingKey /// public string? ReferenceID { - get - { - if (!this.Properties.TryGetValue("reference_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reference_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } } + /// public override void Validate() { this.Cadence.Validate(); _ = this.ItemID; this.ModelType.Validate(); _ = this.Name; - foreach (var item in this.UnitWithProrationConfig.Values) - { - _ = item; - } + this.UnitWithProrationConfig.Validate(); _ = this.BillableMetricID; _ = this.BilledInAdvance; this.BillingCycleConfiguration?.Validate(); @@ -395,30 +251,498 @@ public override void Validate() _ = this.FixedPriceQuantity; _ = this.InvoiceGroupingKey; this.InvoicingCycleConfiguration?.Validate(); - if (this.Metadata != null) - { - foreach (var item in this.Metadata.Values) - { - _ = item; - } - } + _ = this.Metadata; _ = this.ReferenceID; } public NewSubscriptionUnitWithProrationPrice() { } + public NewSubscriptionUnitWithProrationPrice( + NewSubscriptionUnitWithProrationPrice newSubscriptionUnitWithProrationPrice + ) + : base(newSubscriptionUnitWithProrationPrice) { } + + public NewSubscriptionUnitWithProrationPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - NewSubscriptionUnitWithProrationPrice(Generic::Dictionary properties) + [SetsRequiredMembers] + NewSubscriptionUnitWithProrationPrice(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static NewSubscriptionUnitWithProrationPrice FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class NewSubscriptionUnitWithProrationPriceFromRaw + : IFromRawJson +{ + /// + public NewSubscriptionUnitWithProrationPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => NewSubscriptionUnitWithProrationPrice.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(NewSubscriptionUnitWithProrationPriceCadenceConverter))] +public enum NewSubscriptionUnitWithProrationPriceCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class NewSubscriptionUnitWithProrationPriceCadenceConverter + : JsonConverter +{ + public override NewSubscriptionUnitWithProrationPriceCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => NewSubscriptionUnitWithProrationPriceCadence.Annual, + "semi_annual" => NewSubscriptionUnitWithProrationPriceCadence.SemiAnnual, + "monthly" => NewSubscriptionUnitWithProrationPriceCadence.Monthly, + "quarterly" => NewSubscriptionUnitWithProrationPriceCadence.Quarterly, + "one_time" => NewSubscriptionUnitWithProrationPriceCadence.OneTime, + "custom" => NewSubscriptionUnitWithProrationPriceCadence.Custom, + _ => (NewSubscriptionUnitWithProrationPriceCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitWithProrationPriceCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionUnitWithProrationPriceCadence.Annual => "annual", + NewSubscriptionUnitWithProrationPriceCadence.SemiAnnual => "semi_annual", + NewSubscriptionUnitWithProrationPriceCadence.Monthly => "monthly", + NewSubscriptionUnitWithProrationPriceCadence.Quarterly => "quarterly", + NewSubscriptionUnitWithProrationPriceCadence.OneTime => "one_time", + NewSubscriptionUnitWithProrationPriceCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// The pricing model type +/// +[JsonConverter(typeof(NewSubscriptionUnitWithProrationPriceModelTypeConverter))] +public enum NewSubscriptionUnitWithProrationPriceModelType +{ + UnitWithProration, +} + +sealed class NewSubscriptionUnitWithProrationPriceModelTypeConverter + : JsonConverter +{ + public override NewSubscriptionUnitWithProrationPriceModelType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unit_with_proration" => + NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration, + _ => (NewSubscriptionUnitWithProrationPriceModelType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitWithProrationPriceModelType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + NewSubscriptionUnitWithProrationPriceModelType.UnitWithProration => + "unit_with_proration", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for unit_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.UnitWithProrationConfig, + global::Orb.Models.Subscriptions.UnitWithProrationConfigFromRaw + >) +)] +public sealed record class UnitWithProrationConfig : JsonModel +{ + /// + /// Rate per unit of usage + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + } + + public UnitWithProrationConfig() { } + + public UnitWithProrationConfig( + global::Orb.Models.Subscriptions.UnitWithProrationConfig unitWithProrationConfig + ) + : base(unitWithProrationConfig) { } + + public UnitWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UnitWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.UnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public UnitWithProrationConfig(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class UnitWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.UnitWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.UnitWithProrationConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(NewSubscriptionUnitWithProrationPriceConversionRateConfigConverter))] +public record class NewSubscriptionUnitWithProrationPriceConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public NewSubscriptionUnitWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionUnitWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public NewSubscriptionUnitWithProrationPriceConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitWithProrationPriceConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitWithProrationPriceConversionRateConfig" + ), + }; + } + + public static implicit operator NewSubscriptionUnitWithProrationPriceConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator NewSubscriptionUnitWithProrationPriceConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of NewSubscriptionUnitWithProrationPriceConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(NewSubscriptionUnitWithProrationPriceConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class NewSubscriptionUnitWithProrationPriceConversionRateConfigConverter + : JsonConverter +{ + public override NewSubscriptionUnitWithProrationPriceConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new NewSubscriptionUnitWithProrationPriceConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + NewSubscriptionUnitWithProrationPriceConversionRateConfig value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/Cadence.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/Cadence.cs deleted file mode 100644 index 40163e86..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/Cadence.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties; - -/// -/// The cadence to bill for this price on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Cadence(string value) : Orb::IEnum -{ - public static readonly Cadence Annual = new("annual"); - - public static readonly Cadence SemiAnnual = new("semi_annual"); - - public static readonly Cadence Monthly = new("monthly"); - - public static readonly Cadence Quarterly = new("quarterly"); - - public static readonly Cadence OneTime = new("one_time"); - - public static readonly Cadence Custom = new("custom"); - - readonly string _value = value; - - public enum Value - { - Annual, - SemiAnnual, - Monthly, - Quarterly, - OneTime, - Custom, - } - - public Value Known() => - _value switch - { - "annual" => Value.Annual, - "semi_annual" => Value.SemiAnnual, - "monthly" => Value.Monthly, - "quarterly" => Value.Quarterly, - "one_time" => Value.OneTime, - "custom" => Value.Custom, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Cadence FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ConversionRateConfig.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ConversionRateConfig.cs deleted file mode 100644 index d1fc6acf..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ConversionRateConfig.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ConversionRateConfigVariants = Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties.ConversionRateConfigVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties; - -/// -/// The configuration for the rate of the price currency to the invoicing currency. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class ConversionRateConfig -{ - internal ConversionRateConfig() { } - - public static ConversionRateConfigVariants::UnitConversionRateConfig Create( - Models::UnitConversionRateConfig value - ) => new(value); - - public static ConversionRateConfigVariants::TieredConversionRateConfig Create( - Models::TieredConversionRateConfig value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs deleted file mode 100644 index 421a91c9..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ConversionRateConfigVariants/All.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Models = Orb.Models; -using NewSubscriptionUnitWithProrationPriceProperties = Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties.ConversionRateConfigVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnitConversionRateConfig(Models::UnitConversionRateConfig Value) - : NewSubscriptionUnitWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static UnitConversionRateConfig From(Models::UnitConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class TieredConversionRateConfig(Models::TieredConversionRateConfig Value) - : NewSubscriptionUnitWithProrationPriceProperties::ConversionRateConfig, - Orb::IVariant -{ - public static TieredConversionRateConfig From(Models::TieredConversionRateConfig value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ModelType.cs b/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ModelType.cs deleted file mode 100644 index f4f9c707..00000000 --- a/src/Orb/Models/Subscriptions/NewSubscriptionUnitWithProrationPriceProperties/ModelType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.NewSubscriptionUnitWithProrationPriceProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ModelType(string value) : Orb::IEnum -{ - public static readonly ModelType UnitWithProration = new("unit_with_proration"); - - readonly string _value = value; - - public enum Value - { - UnitWithProration, - } - - public Value Known() => - _value switch - { - "unit_with_proration" => Value.UnitWithProration, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ModelType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/Subscription.cs b/src/Orb/Models/Subscriptions/Subscription.cs index 4f8d6d74..1ca4218d 100644 --- a/src/Orb/Models/Subscriptions/Subscription.cs +++ b/src/Orb/Models/Subscriptions/Subscription.cs @@ -1,12 +1,12 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Customers = Orb.Models.Customers; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; using Plans = Orb.Models.Plans; -using Serialization = System.Text.Json.Serialization; -using SubscriptionProperties = Orb.Models.Subscriptions.SubscriptionProperties; using System = System; namespace Orb.Models.Subscriptions; @@ -15,36 +15,30 @@ namespace Orb.Models.Subscriptions; /// A [subscription](/core-concepts#subscription) represents the purchase of a plan /// by a customer. /// -/// By default, subscriptions begin on the day that they're created and renew automatically -/// for each billing cycle at the cadence that's configured in the plan definition. +/// By default, subscriptions begin on the day that they're created and renew +/// automatically for each billing cycle at the cadence that's configured in the +/// plan definition. /// -/// Subscriptions also default to **beginning of month alignment**, which means the -/// first invoice issued for the subscription will have pro-rated charges between +/// Subscriptions also default to **beginning of month alignment**, which means +/// the first invoice issued for the subscription will have pro-rated charges between /// the `start_date` and the first of the following month. Subsequent billing periods /// will always start and end on a month boundary (e.g. subsequent month starts for -/// monthly billing). +/// monthly billing). /// -/// Depending on the plan configuration, any _flat_ recurring fees will be billed +/// Depending on the plan configuration, any _flat_ recurring fees will be billed /// either at the beginning (in-advance) or end (in-arrears) of each billing cycle. /// Plans default to **in-advance billing**. Usage-based fees are billed in arrears /// as usage is accumulated. In the normal course of events, you can expect an invoice /// to contain usage-based charges for the previous period, and a recurring fee for -/// the following period. +/// the following period. /// -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Subscription : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Subscription : JsonModel { public required string ID { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } } /// @@ -52,53 +46,24 @@ public required string ID /// public required long? ActivePlanPhaseOrder { - get - { - if ( - !this.Properties.TryGetValue( - "active_plan_phase_order", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "active_plan_phase_order", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["active_plan_phase_order"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawData, "active_plan_phase_order"); } + init { JsonModel.Set(this._rawData, "active_plan_phase_order", value); } } /// /// The adjustment intervals for this subscription sorted by the start_date of /// the adjustment interval. /// - public required Generic::List AdjustmentIntervals + public required IReadOnlyList AdjustmentIntervals { get { - if (!this.Properties.TryGetValue("adjustment_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("adjustment_intervals"); - } - set - { - this.Properties["adjustment_intervals"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass>( + this.RawData, + "adjustment_intervals" ); } + init { JsonModel.Set(this._rawData, "adjustment_intervals", value); } } /// @@ -108,82 +73,41 @@ public required long? ActivePlanPhaseOrder /// public required bool? AutoCollection { - get - { - if (!this.Properties.TryGetValue("auto_collection", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "auto_collection", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawData, "auto_collection"); } + init { JsonModel.Set(this._rawData, "auto_collection", value); } } - public required Models::BillingCycleAnchorConfiguration BillingCycleAnchorConfiguration + public required BillingCycleAnchorConfiguration BillingCycleAnchorConfiguration { get { - if ( - !this.Properties.TryGetValue( - "billing_cycle_anchor_configuration", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_anchor_configuration", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("billing_cycle_anchor_configuration"); - } - set - { - this.Properties["billing_cycle_anchor_configuration"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "billing_cycle_anchor_configuration" + ); } + init { JsonModel.Set(this._rawData, "billing_cycle_anchor_configuration", value); } } /// /// The day of the month on which the billing cycle is anchored. If the maximum - /// number of days in a month is greater than this value, the last day of the month - /// is the billing cycle day (e.g. billing_cycle_day=31 for April means the billing - /// period begins on the 30th. + /// number of days in a month is greater than this value, the last day of the + /// month is the billing cycle day (e.g. billing_cycle_day=31 for April means + /// the billing period begins on the 30th. /// public required long BillingCycleDay { - get - { - if (!this.Properties.TryGetValue("billing_cycle_day", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billing_cycle_day", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_day"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullStruct(this.RawData, "billing_cycle_day"); } + init { JsonModel.Set(this._rawData, "billing_cycle_day", value); } } - public required System::DateTime CreatedAt + public required System::DateTimeOffset CreatedAt { get { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "created_at", value); } } /// @@ -191,28 +115,16 @@ public required long BillingCycleDay /// that the instant returned is not part of the billing period. Set to null for /// subscriptions that are not currently active. /// - public required System::DateTime? CurrentBillingPeriodEndDate + public required System::DateTimeOffset? CurrentBillingPeriodEndDate { get { - if ( - !this.Properties.TryGetValue( - "current_billing_period_end_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "current_billing_period_end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["current_billing_period_end_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "current_billing_period_end_date" + ); } + init { JsonModel.Set(this._rawData, "current_billing_period_end_date", value); } } /// @@ -220,194 +132,113 @@ public required long BillingCycleDay /// the instant returned is exactly the beginning of the billing period. Set to /// null if the subscription is not currently active. /// - public required System::DateTime? CurrentBillingPeriodStartDate + public required System::DateTimeOffset? CurrentBillingPeriodStartDate { get { - if ( - !this.Properties.TryGetValue( - "current_billing_period_start_date", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "current_billing_period_start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["current_billing_period_start_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawData, + "current_billing_period_start_date" + ); } + init { JsonModel.Set(this._rawData, "current_billing_period_start_date", value); } } /// /// A customer is a buyer of your products, and the other party to the billing relationship. /// - /// In Orb, customers are assigned system generated identifiers automatically, - /// but it's often desirable to have these match existing identifiers in your system. - /// To avoid having to denormalize Orb ID information, you can pass in an `external_customer_id` - /// with your own identifier. See [Customer ID Aliases](/events-and-metrics/customer-aliases) - /// for further information about how these aliases work in Orb. + /// In Orb, customers are assigned system generated identifiers automatically, + /// but it's often desirable to have these match existing identifiers in your + /// system. To avoid having to denormalize Orb ID information, you can pass in + /// an `external_customer_id` with your own identifier. See [Customer ID Aliases](/events-and-metrics/customer-aliases) + /// for further information about how these aliases work in Orb. /// - /// In addition to having an identifier in your system, a customer may exist in - /// a payment provider solution like Stripe. Use the `payment_provider_id` and the - /// `payment_provider` enum field to express this mapping. + /// In addition to having an identifier in your system, a customer may + /// exist in a payment provider solution like Stripe. Use the `payment_provider_id` + /// and the `payment_provider` enum field to express this mapping. /// - /// A customer also has a timezone (from the standard [IANA timezone database](https://www.iana.org/time-zones)), + /// A customer also has a timezone (from the standard [IANA timezone database](https://www.iana.org/time-zones)), /// which defaults to your account's timezone. See [Timezone localization](/essentials/timezones) - /// for information on what this timezone parameter influences within Orb. + /// for information on what this timezone parameter influences within Orb. /// - public required Customers::Customer Customer + public required Customer Customer { - get - { - if (!this.Properties.TryGetValue("customer", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "customer", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("customer"); - } - set { this.Properties["customer"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "customer"); } + init { JsonModel.Set(this._rawData, "customer", value); } } /// - /// Determines the default memo on this subscriptions' invoices. Note that if this - /// is not provided, it is determined by the plan configuration. + /// Determines the default memo on this subscriptions' invoices. Note that if + /// this is not provided, it is determined by the plan configuration. /// public required string? DefaultInvoiceMemo { - get - { - if (!this.Properties.TryGetValue("default_invoice_memo", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "default_invoice_memo", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawData, "default_invoice_memo", value); } } /// /// The discount intervals for this subscription sorted by the start_date. This /// field is deprecated in favor of `adjustment_intervals`. /// - public required Generic::List DiscountIntervals + [System::Obsolete("deprecated")] + public required IReadOnlyList DiscountIntervals { get { - if (!this.Properties.TryGetValue("discount_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("discount_intervals"); - } - set - { - this.Properties["discount_intervals"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_intervals" + ); } + init { JsonModel.Set(this._rawData, "discount_intervals", value); } } /// /// The date Orb stops billing for this subscription. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } - public required Generic::List FixedFeeQuantitySchedule + public required IReadOnlyList FixedFeeQuantitySchedule { get { - if ( - !this.Properties.TryGetValue( - "fixed_fee_quantity_schedule", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "fixed_fee_quantity_schedule", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("fixed_fee_quantity_schedule"); - } - set - { - this.Properties["fixed_fee_quantity_schedule"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "fixed_fee_quantity_schedule" + ); } + init { JsonModel.Set(this._rawData, "fixed_fee_quantity_schedule", value); } } public required string? InvoicingThreshold { - get - { - if (!this.Properties.TryGetValue("invoicing_threshold", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "invoicing_threshold", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["invoicing_threshold"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "invoicing_threshold"); } + init { JsonModel.Set(this._rawData, "invoicing_threshold", value); } } /// /// The maximum intervals for this subscription sorted by the start_date. This /// field is deprecated in favor of `adjustment_intervals`. /// - public required Generic::List MaximumIntervals + [System::Obsolete("deprecated")] + public required IReadOnlyList MaximumIntervals { get { - if (!this.Properties.TryGetValue("maximum_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "maximum_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("maximum_intervals"); - } - set - { - this.Properties["maximum_intervals"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "maximum_intervals" + ); } + init { JsonModel.Set(this._rawData, "maximum_intervals", value); } } /// @@ -416,43 +247,30 @@ public required string? InvoicingThreshold /// to `null`, and the entire metadata mapping can be cleared by setting `metadata` /// to `null`. /// - public required Generic::Dictionary Metadata + public required IReadOnlyDictionary Metadata { get { - if (!this.Properties.TryGetValue("metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("metadata"); + return JsonModel.GetNotNullClass>(this.RawData, "metadata"); } - set { this.Properties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "metadata", value); } } /// /// The minimum intervals for this subscription sorted by the start_date. This /// field is deprecated in favor of `adjustment_intervals`. /// - public required Generic::List MinimumIntervals + [System::Obsolete("deprecated")] + public required IReadOnlyList MinimumIntervals { get { - if (!this.Properties.TryGetValue("minimum_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "minimum_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("minimum_intervals"); - } - set - { - this.Properties["minimum_intervals"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "minimum_intervals" + ); } + init { JsonModel.Set(this._rawData, "minimum_intervals", value); } } /// @@ -460,166 +278,100 @@ public required string? InvoicingThreshold /// public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } /// - /// Determines the difference between the invoice issue date for subscription invoices - /// as the date that they are due. A value of `0` here represents that the invoice - /// is due on issue, whereas a value of `30` represents that the customer has a - /// month to pay the invoice. + /// Determines the difference between the invoice issue date for subscription + /// invoices as the date that they are due. A value of `0` here represents that + /// the invoice is due on issue, whereas a value of `30` represents that the customer + /// has a month to pay the invoice. /// public required long NetTerms { - get - { - if (!this.Properties.TryGetValue("net_terms", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "net_terms", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "net_terms"); } + init { JsonModel.Set(this._rawData, "net_terms", value); } } /// /// A pending subscription change if one exists on this subscription. /// - public required Models::SubscriptionChangeMinified? PendingSubscriptionChange + public required SubscriptionChangeMinified? PendingSubscriptionChange { get { - if ( - !this.Properties.TryGetValue( - "pending_subscription_change", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "pending_subscription_change", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["pending_subscription_change"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawData, + "pending_subscription_change" + ); } + init { JsonModel.Set(this._rawData, "pending_subscription_change", value); } } /// - /// The [Plan](/core-concepts#plan-and-price) resource represents a plan that can - /// be subscribed to by a customer. Plans define the billing behavior of the subscription. - /// You can see more about how to configure prices in the [Price resource](/reference/price). + /// The [Plan](/core-concepts#plan-and-price) resource represents a plan that + /// can be subscribed to by a customer. Plans define the billing behavior of + /// the subscription. You can see more about how to configure prices in the [Price resource](/reference/price). /// public required Plans::Plan? Plan { - get - { - if (!this.Properties.TryGetValue("plan", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("plan", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["plan"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "plan"); } + init { JsonModel.Set(this._rawData, "plan", value); } } /// /// The price intervals for this subscription. /// - public required Generic::List PriceIntervals + public required IReadOnlyList PriceIntervals { get { - if (!this.Properties.TryGetValue("price_intervals", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_intervals", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("price_intervals"); + return JsonModel.GetNotNullClass>(this.RawData, "price_intervals"); } - set { this.Properties["price_intervals"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "price_intervals", value); } } - public required Models::CouponRedemption? RedeemedCoupon + public required CouponRedemption? RedeemedCoupon { get { - if (!this.Properties.TryGetValue("redeemed_coupon", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "redeemed_coupon", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableClass(this.RawData, "redeemed_coupon"); } - set { this.Properties["redeemed_coupon"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "redeemed_coupon", value); } } /// /// The date Orb starts billing for this subscription. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } - public required SubscriptionProperties::Status Status + public required ApiEnum Status { get { - if (!this.Properties.TryGetValue("status", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "status", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("status"); + return JsonModel.GetNotNullClass>( + this.RawData, + "status" + ); } - set { this.Properties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "status", value); } } - public required Models::SubscriptionTrialInfo TrialInfo + public required SubscriptionTrialInfo TrialInfo { - get - { - if (!this.Properties.TryGetValue("trial_info", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "trial_info", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("trial_info"); - } - set { this.Properties["trial_info"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "trial_info"); } + init { JsonModel.Set(this._rawData, "trial_info", value); } } + /// public override void Validate() { _ = this.ID; @@ -650,10 +402,7 @@ public override void Validate() { item.Validate(); } - foreach (var item in this.Metadata.Values) - { - _ = item; - } + _ = this.Metadata; foreach (var item in this.MinimumIntervals) { item.Validate(); @@ -672,20 +421,444 @@ public override void Validate() this.TrialInfo.Validate(); } + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] public Subscription() { } + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] + public Subscription(Subscription subscription) + : base(subscription) { } + + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] + public Subscription(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Subscription(Generic::Dictionary properties) + [System::Obsolete( + "Required properties are deprecated: discount_intervals, maximum_intervals, minimum_intervals" + )] + [SetsRequiredMembers] + Subscription(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static Subscription FromRawUnchecked( - Generic::Dictionary properties + /// + public static Subscription FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionFromRaw : IFromRawJson +{ + /// + public Subscription FromRawUnchecked(IReadOnlyDictionary rawData) => + Subscription.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DiscountIntervalConverter))] +public record class DiscountInterval +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public System::DateTimeOffset? EndDate + { + get + { + return Match( + amount: (x) => x.EndDate, + percentage: (x) => x.EndDate, + usage: (x) => x.EndDate + ); + } + } + + public System::DateTimeOffset StartDate + { + get + { + return Match( + amount: (x) => x.StartDate, + percentage: (x) => x.StartDate, + usage: (x) => x.StartDate + ); + } + } + + public DiscountInterval(AmountDiscountInterval value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DiscountInterval(PercentageDiscountInterval value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DiscountInterval(UsageDiscountInterval value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public DiscountInterval(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `AmountDiscountInterval` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out AmountDiscountInterval? value) + { + value = this.Value as AmountDiscountInterval; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `PercentageDiscountInterval` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out PercentageDiscountInterval? value) + { + value = this.Value as PercentageDiscountInterval; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUsage(out var value)) { + /// // `value` is of type `UsageDiscountInterval` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUsage([NotNullWhen(true)] out UsageDiscountInterval? value) + { + value = this.Value as UsageDiscountInterval; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (AmountDiscountInterval value) => {...}, + /// (PercentageDiscountInterval value) => {...}, + /// (UsageDiscountInterval value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action amount, + System::Action percentage, + System::Action usage + ) + { + switch (this.Value) + { + case AmountDiscountInterval value: + amount(value); + break; + case PercentageDiscountInterval value: + percentage(value); + break; + case UsageDiscountInterval value: + usage(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of DiscountInterval" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (AmountDiscountInterval value) => {...}, + /// (PercentageDiscountInterval value) => {...}, + /// (UsageDiscountInterval value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func amount, + System::Func percentage, + System::Func usage + ) + { + return this.Value switch + { + AmountDiscountInterval value => amount(value), + PercentageDiscountInterval value => percentage(value), + UsageDiscountInterval value => usage(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of DiscountInterval" + ), + }; + } + + public static implicit operator DiscountInterval(AmountDiscountInterval value) => new(value); + + public static implicit operator DiscountInterval(PercentageDiscountInterval value) => + new(value); + + public static implicit operator DiscountInterval(UsageDiscountInterval value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of DiscountInterval"); + } + this.Switch( + (amount) => amount.Validate(), + (percentage) => percentage.Validate(), + (usage) => usage.Validate() + ); + } + + public virtual bool Equals(DiscountInterval? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class DiscountIntervalConverter : JsonConverter +{ + public override DiscountInterval? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); + } + catch + { + discountType = null; + } + + switch (discountType) + { + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new DiscountInterval(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + DiscountInterval value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(SubscriptionStatusConverter))] +public enum SubscriptionStatus +{ + Active, + Ended, + Upcoming, +} + +sealed class SubscriptionStatusConverter : JsonConverter +{ + public override SubscriptionStatus Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => SubscriptionStatus.Active, + "ended" => SubscriptionStatus.Ended, + "upcoming" => SubscriptionStatus.Upcoming, + _ => (SubscriptionStatus)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionStatus value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionStatus.Active => "active", + SubscriptionStatus.Ended => "ended", + SubscriptionStatus.Upcoming => "upcoming", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionCancelParams.cs b/src/Orb/Models/Subscriptions/SubscriptionCancelParams.cs index d167bb9b..e44ab0ab 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionCancelParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionCancelParams.cs @@ -1,92 +1,91 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionCancelParamsProperties = Orb.Models.Subscriptions.SubscriptionCancelParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; /// -/// This endpoint can be used to cancel an existing subscription. It returns the -/// serialized subscription object with an `end_date` parameter that signifies when -/// the subscription will transition to an ended state. +/// This endpoint can be used to cancel an existing subscription. It returns the serialized +/// subscription object with an `end_date` parameter that signifies when the subscription +/// will transition to an ended state. /// -/// The body parameter `cancel_option` determines the cancellation behavior. Orb -/// supports three cancellation options: - `end_of_subscription_term`: stops the -/// subscription from auto-renewing. Subscriptions that have been cancelled with -/// this option can still incur charges for the remainder of their term: - Issuing +/// The body parameter `cancel_option` determines the cancellation behavior. +/// Orb supports three cancellation options: - `end_of_subscription_term`: stops +/// the subscription from auto-renewing. Subscriptions that have been cancelled with +/// this option can still incur charges for the remainder of their term: - Issuing /// this cancellation request for a monthly subscription will keep the subscription /// active until the start of the subsequent month, and potentially issue an /// invoice for any usage charges incurred in the intervening period. - -/// Issuing this cancellation request for a quarterly subscription will keep the -/// subscription active until the end of the quarter and potentially issue an -/// invoice for any usage charges incurred in the intervening period. - Issuing -/// this cancellation request for a yearly subscription will keep the subscription -/// active for the full year. For example, a yearly subscription starting on -/// 2021-11-01 and cancelled on 2021-12-08 will remain active until 2022-11-01 -/// and potentially issue charges in the intervening months for any recurring monthly -/// usage charges in its plan. - **Note**: If a subscription's plan contains -/// prices with difference cadences, the end of term date will be determined -/// by the largest cadence value. For example, cancelling end of term for a subscription -/// with a quarterly fixed fee with a monthly usage fee will result in the subscription -/// ending at the end of the quarter. +/// Issuing this cancellation request for a quarterly subscription will keep the subscription +/// active until the end of the quarter and potentially issue an invoice for +/// any usage charges incurred in the intervening period. - Issuing this cancellation +/// request for a yearly subscription will keep the subscription active for the full +/// year. For example, a yearly subscription starting on 2021-11-01 and cancelled +/// on 2021-12-08 will remain active until 2022-11-01 and potentially issue +/// charges in the intervening months for any recurring monthly usage charges +/// in its plan. - **Note**: If a subscription's plan contains prices with difference +/// cadences, the end of term date will be determined by the largest cadence +/// value. For example, cancelling end of term for a subscription with a quarterly +/// fixed fee with a monthly usage fee will result in the subscription ending at the +/// end of the quarter. /// -/// - `immediate`: ends the subscription immediately, setting the `end_date` to the -/// current time: - Subscriptions that have been cancelled with this option will -/// be invoiced immediately. This invoice will include any usage fees incurred +/// - `immediate`: ends the subscription immediately, setting the `end_date` +/// to the current time: - Subscriptions that have been cancelled with this option +/// will be invoiced immediately. This invoice will include any usage fees incurred /// in the billing period up to the cancellation, along with any prorated recurring /// fees for the billing period, if applicable. - **Note**: If the subscription /// has a recurring fee that was paid in-advance, the prorated amount for the -/// remaining time period will be added to the [customer's balance](list-balance-transactions) -/// upon immediate cancellation. However, if the customer is ineligible to use -/// the customer balance, the subscription cannot be cancelled immediately. +/// remaining time period will be added to the [customer's balance](list-balance-transactions) +/// upon immediate cancellation. However, if the customer is ineligible to +/// use the customer balance, the subscription cannot be cancelled immediately. /// -/// - `requested_date`: ends the subscription on a specified date, which requires +/// - `requested_date`: ends the subscription on a specified date, which requires /// a `cancellation_date` to be passed in. If no timezone is provided, the customer's /// timezone is used. For example, a subscription starting on January 1st with /// a monthly price can be set to be cancelled on the first of any month after January /// 1st (e.g. March 1st, April 1st, May 1st). A subscription with multiple prices -/// with different cadences defines the "term" to be the highest cadence of the prices. +/// with different cadences defines the "term" to be the highest cadence of the prices. /// -/// Upcoming subscriptions are only eligible for immediate cancellation, which will -/// set the `end_date` equal to the `start_date` upon cancellation. +/// Upcoming subscriptions are only eligible for immediate cancellation, which +/// will set the `end_date` equal to the `start_date` upon cancellation. /// -/// ## Backdated cancellations Orb allows you to cancel a subscription in the past -/// as long as there are no paid invoices between the `requested_date` and the current -/// time. If the cancellation is after the latest issued invoice, Orb will generate -/// a balance refund for the current period. If the cancellation is before the most -/// recently issued invoice, Orb will void the intervening invoice and generate a -/// new one based on the new dates for the subscription. See the section on [cancellation behaviors](/product-catalog/creating-subscriptions#cancellation-behaviors). +/// ## Backdated cancellations Orb allows you to cancel a subscription in the +/// past as long as there are no paid invoices between the `requested_date` and the +/// current time. If the cancellation is after the latest issued invoice, Orb will +/// generate a balance refund for the current period. If the cancellation is before +/// the most recently issued invoice, Orb will void the intervening invoice and generate +/// a new one based on the new dates for the subscription. See the section on [cancellation behaviors](/product-catalog/creating-subscriptions#cancellation-behaviors). /// -public sealed record class SubscriptionCancelParams : Orb::ParamsBase +public sealed record class SubscriptionCancelParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// Determines the timing of subscription cancellation /// - public required SubscriptionCancelParamsProperties::CancelOption CancelOption + public required ApiEnum CancelOption { get { - if (!this.BodyProperties.TryGetValue("cancel_option", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "cancel_option", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("cancel_option"); - } - set - { - this.BodyProperties["cancel_option"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "cancel_option" + ); } + init { JsonModel.Set(this._rawBodyData, "cancel_option", value); } } /// @@ -98,72 +97,153 @@ public bool? AllowInvoiceCreditOrVoid { get { - if ( - !this.BodyProperties.TryGetValue( - "allow_invoice_credit_or_void", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["allow_invoice_credit_or_void"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "allow_invoice_credit_or_void" + ); } + init { JsonModel.Set(this._rawBodyData, "allow_invoice_credit_or_void", value); } } /// - /// The date that the cancellation should take effect. This parameter can only be - /// passed if the `cancel_option` is `requested_date`. + /// The date that the cancellation should take effect. This parameter can only + /// be passed if the `cancel_option` is `requested_date`. /// - public System::DateTime? CancellationDate + public System::DateTimeOffset? CancellationDate { get { - if ( - !this.BodyProperties.TryGetValue("cancellation_date", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["cancellation_date"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawBodyData, + "cancellation_date" ); } + init { JsonModel.Set(this._rawBodyData, "cancellation_date", value); } + } + + public SubscriptionCancelParams() { } + + public SubscriptionCancelParams(SubscriptionCancelParams subscriptionCancelParams) + : base(subscriptionCancelParams) + { + this._rawBodyData = [.. subscriptionCancelParams._rawBodyData]; + } + + public SubscriptionCancelParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionCancelParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionCancelParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/cancel", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// Determines the timing of subscription cancellation +/// +[JsonConverter(typeof(CancelOptionConverter))] +public enum CancelOption +{ + EndOfSubscriptionTerm, + Immediate, + RequestedDate, +} + +sealed class CancelOptionConverter : JsonConverter +{ + public override CancelOption Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "end_of_subscription_term" => CancelOption.EndOfSubscriptionTerm, + "immediate" => CancelOption.Immediate, + "requested_date" => CancelOption.RequestedDate, + _ => (CancelOption)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + CancelOption value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + CancelOption.EndOfSubscriptionTerm => "end_of_subscription_term", + CancelOption.Immediate => "immediate", + CancelOption.RequestedDate => "requested_date", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCancelParamsProperties/CancelOption.cs b/src/Orb/Models/Subscriptions/SubscriptionCancelParamsProperties/CancelOption.cs deleted file mode 100644 index f90bee87..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCancelParamsProperties/CancelOption.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCancelParamsProperties; - -/// -/// Determines the timing of subscription cancellation -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class CancelOption(string value) : Orb::IEnum -{ - public static readonly CancelOption EndOfSubscriptionTerm = new("end_of_subscription_term"); - - public static readonly CancelOption Immediate = new("immediate"); - - public static readonly CancelOption RequestedDate = new("requested_date"); - - readonly string _value = value; - - public enum Value - { - EndOfSubscriptionTerm, - Immediate, - RequestedDate, - } - - public Value Known() => - _value switch - { - "end_of_subscription_term" => Value.EndOfSubscriptionTerm, - "immediate" => Value.Immediate, - "requested_date" => Value.RequestedDate, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static CancelOption FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParams.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParams.cs index 4b1d3233..3dbd19ba 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionCreateParams.cs @@ -1,265 +1,262 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using SubscriptionCreateParamsProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; /// -/// A subscription represents the purchase of a plan by a customer. The customer -/// is identified by either the `customer_id` or the `external_customer_id`, and -/// exactly one of these fields must be provided. +/// A subscription represents the purchase of a plan by a customer. The customer is +/// identified by either the `customer_id` or the `external_customer_id`, and exactly +/// one of these fields must be provided. /// -/// By default, subscriptions begin on the day that they're created and renew automatically -/// for each billing cycle at the cadence that's configured in the plan definition. +/// By default, subscriptions begin on the day that they're created and renew +/// automatically for each billing cycle at the cadence that's configured in the +/// plan definition. /// -/// The default configuration for subscriptions in Orb is **In-advance billing** and -/// **Beginning of month alignment** (see [Subscription](/core-concepts##subscription) -/// for more details). +/// The default configuration for subscriptions in Orb is **In-advance billing** +/// and **Beginning of month alignment** (see [Subscription](/core-concepts##subscription) +/// for more details). /// -/// In order to change the alignment behavior, Orb also supports billing subscriptions +/// In order to change the alignment behavior, Orb also supports billing subscriptions /// on the day of the month they are created. If `align_billing_with_subscription_start_date /// = true` is specified, subscriptions have billing cycles that are aligned with /// their `start_date`. For example, a subscription that begins on January 15th will /// have a billing cycle from January 15th to February 15th. Every subsequent billing -/// cycle will continue to start and invoice on the 15th. +/// cycle will continue to start and invoice on the 15th. /// -/// If the "day" value is greater than the number of days in the month, the next billing -/// cycle will start at the end of the month. For example, if the start_date is January -/// 31st, the next billing cycle will start on February 28th. +/// If the "day" value is greater than the number of days in the month, the +/// next billing cycle will start at the end of the month. For example, if the start_date +/// is January 31st, the next billing cycle will start on February 28th. /// -/// If a customer was created with a currency, Orb only allows subscribing the customer -/// to a plan with a matching `invoicing_currency`. If the customer does not have -/// a currency set, on subscription creation, we set the customer's currency to be -/// the `invoicing_currency` of the plan. +/// If a customer was created with a currency, Orb only allows subscribing +/// the customer to a plan with a matching `invoicing_currency`. If the customer +/// does not have a currency set, on subscription creation, we set the customer's +/// currency to be the `invoicing_currency` of the plan. /// -/// ## Customize your customer's subscriptions +/// ## Customize your customer's subscriptions /// -/// Prices and adjustments in a plan can be added, removed, or replaced for the subscription -/// being created. This is useful when a customer has prices that differ from the -/// default prices for a specific plan. +/// Prices and adjustments in a plan can be added, removed, or replaced for +/// the subscription being created. This is useful when a customer has prices that +/// differ from the default prices for a specific plan. /// -/// This feature is only available for accounts that have migrated to Subscription -/// Overrides Version 2. You can find your Subscription Overrides Version at the -/// bottom of your [Plans page](https://app.withorb.com/plans) +/// This feature is only available for accounts that have migrated to +/// Subscription Overrides Version 2. You can find your Subscription Overrides Version +/// at the bottom of your [Plans page](https://app.withorb.com/plans) /// -/// ### Adding Prices +/// ### Adding Prices /// -/// To add prices, provide a list of objects with the key `add_prices`. An object +/// To add prices, provide a list of objects with the key `add_prices`. An object /// in the list must specify an existing add-on price with a `price_id` or `external_price_id` /// field, or create a new add-on price by including an object with the key `price`, /// identical to what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). /// See the [Price resource](/product-catalog/price-configuration) for the specification -/// of different price model configurations possible in this object. +/// of different price model configurations possible in this object. /// -/// If the plan has phases, each object in the list must include a number with `plan_phase_order` -/// key to indicate which phase the price should be added to. +/// If the plan has phases, each object in the list must include a number with +/// `plan_phase_order` key to indicate which phase the price should be added to. /// -/// An object in the list can specify an optional `start_date` and optional `end_date`. -/// This is equivalent to creating a price interval with the [add/edit price intervals -/// endpoint](/api-reference/price-interval/add-or-edit-price-intervals). If unspecified, -/// the start or end date of the phase or subscription will be used. +/// An object in the list can specify an optional `start_date` and optional +/// `end_date`. This is equivalent to creating a price interval with the [add/edit +/// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). +/// If unspecified, the start or end date of the phase or subscription will be used. /// -/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, -/// or `discounts`. This will create adjustments which apply only to this price. +/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, +/// or `discounts`. This will create adjustments which apply only to this price. /// -/// Additionally, an object in the list can specify an optional `reference_id`. This -/// ID can be used to reference this price when [adding an adjustment](#adding-adjustments) +/// Additionally, an object in the list can specify an optional `reference_id`. +/// This ID can be used to reference this price when [adding an adjustment](#adding-adjustments) /// in the same API call. However the ID is _transient_ and cannot be used to refer -/// to the price in future API calls. +/// to the price in future API calls. /// -/// ### Removing Prices +/// ### Removing Prices /// -/// To remove prices, provide a list of objects with the key `remove_prices`. An -/// object in the list must specify a plan price with either a `price_id` or `external_price_id` field. +/// To remove prices, provide a list of objects with the key `remove_prices`. +/// An object in the list must specify a plan price with either a `price_id` or `external_price_id` field. /// -/// ### Replacing Prices +/// ### Replacing Prices /// -/// To replace prices, provide a list of objects with the key `replace_prices`. An -/// object in the list must specify a plan price to replace with the `replaces_price_id` -/// key, and it must specify a price to replace it with by either referencing an existing -/// add-on price with a `price_id` or `external_price_id` field, or by creating a -/// new add-on price by including an object with the key `price`, identical to what -/// would be used in the request body for the [create price endpoint](/api-reference/price/create-price). +/// To replace prices, provide a list of objects with the key `replace_prices`. +/// An object in the list must specify a plan price to replace with the `replaces_price_id` +/// key, and it must specify a price to replace it with by either referencing an +/// existing add-on price with a `price_id` or `external_price_id` field, or by creating +/// a new add-on price by including an object with the key `price`, identical to +/// what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). /// See the [Price resource](/product-catalog/price-configuration) for the specification -/// of different price model configurations possible in this object. +/// of different price model configurations possible in this object. /// -/// For fixed fees, an object in the list can supply a `fixed_price_quantity` instead -/// of a `price`, `price_id`, or `external_price_id` field. This will update only -/// the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. +/// For fixed fees, an object in the list can supply a `fixed_price_quantity` +/// instead of a `price`, `price_id`, or `external_price_id` field. This will update +/// only the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. /// -/// The replacement price will have the same phase, if applicable, and the same start -/// and end dates as the price it replaces. +/// The replacement price will have the same phase, if applicable, and the +/// same start and end dates as the price it replaces. /// -/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, -/// or `discounts`. This will create adjustments which apply only to this price. +/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, +/// or `discounts`. This will create adjustments which apply only to this price. /// -/// Additionally, an object in the list can specify an optional `reference_id`. This -/// ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) +/// Additionally, an object in the list can specify an optional `reference_id`. +/// This ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) /// in the same API call. However the ID is _transient_ and cannot be used to refer -/// to the price in future API calls. +/// to the price in future API calls. /// -/// ### Adding adjustments +/// ### Adding adjustments /// -/// To add adjustments, provide a list of objects with the key `add_adjustments`. +/// To add adjustments, provide a list of objects with the key `add_adjustments`. /// An object in the list must include an object with the key `adjustment`, identical -/// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). +/// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). /// -/// If the plan has phases, each object in the list must include a number with `plan_phase_order` -/// key to indicate which phase the adjustment should be added to. +/// If the plan has phases, each object in the list must include a number with +/// `plan_phase_order` key to indicate which phase the adjustment should be added to. /// -/// An object in the list can specify an optional `start_date` and optional `end_date`. -/// If unspecified, the start or end date of the phase or subscription will be used. +/// An object in the list can specify an optional `start_date` and optional +/// `end_date`. If unspecified, the start or end date of the phase or subscription +/// will be used. /// -/// ### Removing adjustments +/// ### Removing adjustments /// -/// To remove adjustments, provide a list of objects with the key `remove_adjustments`. +/// To remove adjustments, provide a list of objects with the key `remove_adjustments`. /// An object in the list must include a key, `adjustment_id`, with the ID of the -/// adjustment to be removed. +/// adjustment to be removed. /// -/// ### Replacing adjustments +/// ### Replacing adjustments /// -/// To replace adjustments, provide a list of objects with the key `replace_adjustments`. +/// To replace adjustments, provide a list of objects with the key `replace_adjustments`. /// An object in the list must specify a plan adjustment to replace with the `replaces_adjustment_id` /// key, and it must specify an adjustment to replace it with by including an object /// with the key `adjustment`, identical to the adjustment object in the [add/edit -/// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). +/// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). /// -/// The replacement adjustment will have the same phase, if applicable, and the same -/// start and end dates as the adjustment it replaces. +/// The replacement adjustment will have the same phase, if applicable, and +/// the same start and end dates as the adjustment it replaces. /// -/// ## Price overrides (DEPRECATED) +/// ## Price overrides (DEPRECATED) /// -/// Price overrides are being phased out in favor adding/removing/replacing -/// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/create-subscription)) +/// Price overrides are being phased out in favor adding/removing/replacing +/// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/create-subscription)) /// -/// Price overrides are used to update some or all prices in a plan for the specific -/// subscription being created. This is useful when a new customer has negotiated -/// a rate that is unique to the customer. +/// Price overrides are used to update some or all prices in a plan for the +/// specific subscription being created. This is useful when a new customer has negotiated +/// a rate that is unique to the customer. /// -/// To override prices, provide a list of objects with the key `price_overrides`. +/// To override prices, provide a list of objects with the key `price_overrides`. /// The price object in the list of overrides is expected to contain the existing /// price id, the `model_type` and configuration. (See the [Price resource](/product-catalog/price-configuration) /// for the specification of different price model configurations.) The numerical -/// values can be updated, but the billable metric, cadence, type, and name of a price -/// can not be overridden. +/// values can be updated, but the billable metric, cadence, type, and name of a +/// price can not be overridden. /// -/// ### Maximums and Minimums Minimums and maximums, much like price overrides, can -/// be useful when a new customer has negotiated a new or different minimum or maximum -/// spend cap than the default for a given price. If one exists for a price and null -/// is provided for the minimum/maximum override on creation, then there will be no -/// minimum/maximum on the new subscription. If no value is provided, then the default -/// price maximum or minimum is used. +/// ### Maximums and Minimums Minimums and maximums, much like price overrides, +/// can be useful when a new customer has negotiated a new or different minimum or +/// maximum spend cap than the default for a given price. If one exists for a price +/// and null is provided for the minimum/maximum override on creation, then there +/// will be no minimum/maximum on the new subscription. If no value is provided, then +/// the default price maximum or minimum is used. /// -/// To add a minimum for a specific price, add `minimum_amount` to the specific price -/// in the `price_overrides` object. +/// To add a minimum for a specific price, add `minimum_amount` to the specific +/// price in the `price_overrides` object. /// -/// To add a maximum for a specific price, add `maximum_amount` to the specific price -/// in the `price_overrides` object. +/// To add a maximum for a specific price, add `maximum_amount` to the specific +/// price in the `price_overrides` object. /// -/// ### Minimum override example +/// ### Minimum override example /// -/// Price minimum override example: +/// Price minimum override example: /// -/// ```json { ... "id": "price_id", "model_type": "unit", "unit_config": { -/// "unit_amount": "0.50" }, "minimum_amount": "100.00" ... } ``` +/// ```json { ... "id": "price_id", "model_type": "unit", "unit_config": +/// { "unit_amount": "0.50" }, "minimum_amount": "100.00" ... } ``` /// -/// Removing an existing minimum example ```json { ... "id": "price_id", "model_type": -/// "unit", "unit_config": { "unit_amount": "0.50" }, "minimum_amount": -/// null ... } ``` +/// Removing an existing minimum example ```json { ... "id": "price_id", +/// "model_type": "unit", "unit_config": { "unit_amount": "0.50" }, "minimum_amount": +/// null ... } ``` /// -/// ### Discounts Discounts, like price overrides, can be useful when a new customer -/// has negotiated a new or different discount than the default for a price. If a -/// discount exists for a price and a null discount is provided on creation, then -/// there will be no discount on the new subscription. +/// ### Discounts Discounts, like price overrides, can be useful when a new +/// customer has negotiated a new or different discount than the default for a price. +/// If a discount exists for a price and a null discount is provided on creation, +/// then there will be no discount on the new subscription. /// -/// To add a discount for a specific price, add `discount` to the price in the `price_overrides` -/// object. Discount should be a dictionary of the format: ```ts { "discount_type": -/// "amount" | "percentage" | "usage", "amount_discount": string, "percentage_discount": -/// string, "usage_discount": string } ``` where either `amount_discount`, `percentage_discount`, -/// or `usage_discount` is provided. +/// To add a discount for a specific price, add `discount` to the price in +/// the `price_overrides` object. Discount should be a dictionary of the format: ```ts +/// { "discount_type": "amount" | "percentage" | "usage", "amount_discount": +/// string, "percentage_discount": string, "usage_discount": string } ``` where +/// either `amount_discount`, `percentage_discount`, or `usage_discount` is provided. /// -/// Price discount example ```json { ... "id": "price_id", "model_type": "unit", -/// "unit_config": { "unit_amount": "0.50" }, "discount": {"discount_type": -/// "amount", "amount_discount": "175"}, } ``` +/// Price discount example ```json { ... "id": "price_id", "model_type": +/// "unit", "unit_config": { "unit_amount": "0.50" }, "discount": {"discount_type": +/// "amount", "amount_discount": "175"}, } ``` /// -/// Removing an existing discount example ```json { "customer_id": "customer_id", +/// Removing an existing discount example ```json { "customer_id": "customer_id", /// "plan_id": "plan_id", "discount": null, "price_overrides": [ ... ] ... -/// } ``` +/// } ``` /// -/// ## Threshold Billing +/// ## Threshold Billing /// -/// Orb supports invoicing for a subscription when a preconfigured usage threshold -/// is hit. To enable threshold billing, pass in an `invoicing_threshold`, which is -/// specified in the subscription's invoicing currency, when creating a subscription. +/// Orb supports invoicing for a subscription when a preconfigured usage threshold +/// is hit. To enable threshold billing, pass in an `invoicing_threshold`, which +/// is specified in the subscription's invoicing currency, when creating a subscription. /// E.g. pass in `10.00` to issue an invoice when usage amounts hit \$10.00 for a -/// subscription that invoices in USD. +/// subscription that invoices in USD. +/// +/// ## Limits By default, Orb limits the number of subscriptions per customer +/// to 100. /// -public sealed record class SubscriptionCreateParams : Orb::ParamsBase +public sealed record class SubscriptionCreateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } /// /// Additional adjustments to be added to the subscription. (Only available for /// accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? AddAdjustments + public IReadOnlyList? AddAdjustments { get { - if (!this.BodyProperties.TryGetValue("add_adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "add_adjustments" ); } - set - { - this.BodyProperties["add_adjustments"] = Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawBodyData, "add_adjustments", value); } } /// /// Additional prices to be added to the subscription. (Only available for accounts /// that have migrated off of legacy subscription overrides) /// - public Generic::List? AddPrices + public IReadOnlyList? AddPrices { - get - { - if (!this.BodyProperties.TryGetValue("add_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.BodyProperties["add_prices"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass>(this.RawBodyData, "add_prices"); } + init { JsonModel.Set(this._rawBodyData, "add_prices", value); } } public bool? AlignBillingWithSubscriptionStartDate { get { - if ( - !this.BodyProperties.TryGetValue( - "align_billing_with_subscription_start_date", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "align_billing_with_subscription_start_date" + ); } - set + init { - this.BodyProperties["align_billing_with_subscription_start_date"] = - Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "align_billing_with_subscription_start_date", value); } } @@ -270,234 +267,121 @@ public bool? AlignBillingWithSubscriptionStartDate /// public bool? AutoCollection { - get - { - if (!this.BodyProperties.TryGetValue("auto_collection", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_collection"); } + init { JsonModel.Set(this._rawBodyData, "auto_collection", value); } } + [System::Obsolete("deprecated")] public string? AwsRegion { - get - { - if (!this.BodyProperties.TryGetValue("aws_region", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["aws_region"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "aws_region"); } + init { JsonModel.Set(this._rawBodyData, "aws_region", value); } } - public Models::BillingCycleAnchorConfiguration? BillingCycleAnchorConfiguration + public BillingCycleAnchorConfiguration? BillingCycleAnchorConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "billing_cycle_anchor_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawBodyData, + "billing_cycle_anchor_configuration" ); } - set - { - this.BodyProperties["billing_cycle_anchor_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawBodyData, "billing_cycle_anchor_configuration", value); } } /// - /// Redemption code to be used for this subscription. If the coupon cannot be found - /// by its redemption code, or cannot be redeemed, an error response will be returned - /// and the subscription creation or plan change will not be scheduled. + /// Redemption code to be used for this subscription. If the coupon cannot be + /// found by its redemption code, or cannot be redeemed, an error response will + /// be returned and the subscription creation or plan change will not be scheduled. /// public string? CouponRedemptionCode { get { - if ( - !this.BodyProperties.TryGetValue( - "coupon_redemption_code", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["coupon_redemption_code"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawBodyData, "coupon_redemption_code"); } + init { JsonModel.Set(this._rawBodyData, "coupon_redemption_code", value); } } + [System::Obsolete("deprecated")] public double? CreditsOverageRate { get { - if ( - !this.BodyProperties.TryGetValue( - "credits_overage_rate", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["credits_overage_rate"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableStruct(this.RawBodyData, "credits_overage_rate"); } + init { JsonModel.Set(this._rawBodyData, "credits_overage_rate", value); } } /// - /// The currency to use for the subscription. If not specified, the invoicing currency - /// for the plan will be used. + /// The currency to use for the subscription. If not specified, the invoicing + /// currency for the plan will be used. /// public string? Currency { - get - { - if (!this.BodyProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "currency"); } + init { JsonModel.Set(this._rawBodyData, "currency", value); } } public string? CustomerID { - get - { - if (!this.BodyProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "customer_id"); } + init { JsonModel.Set(this._rawBodyData, "customer_id", value); } } /// - /// Determines the default memo on this subscription's invoices. Note that if this - /// is not provided, it is determined by the plan configuration. + /// Determines the default memo on this subscription's invoices. Note that if + /// this is not provided, it is determined by the plan configuration. /// public string? DefaultInvoiceMemo { - get - { - if ( - !this.BodyProperties.TryGetValue( - "default_invoice_memo", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawBodyData, "default_invoice_memo", value); } } - public System::DateTime? EndDate + public System::DateTimeOffset? EndDate { get { - if (!this.BodyProperties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "end_date" + ); } - set { this.BodyProperties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "end_date", value); } } public string? ExternalCustomerID { - get - { - if ( - !this.BodyProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_customer_id"); } + init { JsonModel.Set(this._rawBodyData, "external_customer_id", value); } } - public SubscriptionCreateParamsProperties::ExternalMarketplace? ExternalMarketplace + [System::Obsolete("deprecated")] + public ApiEnum? ExternalMarketplace { get { - if ( - !this.BodyProperties.TryGetValue( - "external_marketplace", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); - } - set - { - this.BodyProperties["external_marketplace"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "external_marketplace" ); } + init { JsonModel.Set(this._rawBodyData, "external_marketplace", value); } } + [System::Obsolete("deprecated")] public string? ExternalMarketplaceReportingID { get { - if ( - !this.BodyProperties.TryGetValue( - "external_marketplace_reporting_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_marketplace_reporting_id"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass( + this.RawBodyData, + "external_marketplace_reporting_id" + ); } + init { JsonModel.Set(this._rawBodyData, "external_marketplace_reporting_id", value); } } /// @@ -506,19 +390,8 @@ public string? ExternalMarketplaceReportingID /// public string? ExternalPlanID { - get - { - if (!this.BodyProperties.TryGetValue("external_plan_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_plan_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_plan_id"); } + init { JsonModel.Set(this._rawBodyData, "external_plan_id", value); } } /// @@ -528,14 +401,8 @@ public string? ExternalPlanID /// public string? Filter { - get - { - if (!this.BodyProperties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["filter"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "filter"); } + init { JsonModel.Set(this._rawBodyData, "filter", value); } } /// @@ -543,51 +410,19 @@ public string? Filter /// public long? InitialPhaseOrder { - get - { - if ( - !this.BodyProperties.TryGetValue( - "initial_phase_order", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["initial_phase_order"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "initial_phase_order"); } + init { JsonModel.Set(this._rawBodyData, "initial_phase_order", value); } } /// - /// When this subscription's accrued usage reaches this threshold, an invoice will - /// be issued for the subscription. If not specified, invoices will only be issued - /// at the end of the billing period. + /// When this subscription's accrued usage reaches this threshold, an invoice + /// will be issued for the subscription. If not specified, invoices will only + /// be issued at the end of the billing period. /// public string? InvoicingThreshold { - get - { - if ( - !this.BodyProperties.TryGetValue( - "invoicing_threshold", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["invoicing_threshold"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "invoicing_threshold"); } + init { JsonModel.Set(this._rawBodyData, "invoicing_threshold", value); } } /// @@ -595,69 +430,50 @@ public string? InvoicingThreshold /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } /// - /// The name to use for the subscription. If not specified, the plan name will be used. + /// The name to use for the subscription. If not specified, the plan name will + /// be used. /// public string? Name { - get - { - if (!this.BodyProperties.TryGetValue("name", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "name"); } + init { JsonModel.Set(this._rawBodyData, "name", value); } } /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. If not provided, this defaults to the value specified in the plan. + /// The net terms determines the difference between the invoice date and the + /// issue date for the invoice. If you intend the invoice to be due on issue, + /// set this to 0. If not provided, this defaults to the value specified in the plan. /// public long? NetTerms { - get - { - if (!this.BodyProperties.TryGetValue("net_terms", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "net_terms"); } + init { JsonModel.Set(this._rawBodyData, "net_terms", value); } } + [System::Obsolete("deprecated")] public double? PerCreditOverageAmount { get { - if ( - !this.BodyProperties.TryGetValue( - "per_credit_overage_amount", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["per_credit_overage_amount"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "per_credit_overage_amount" + ); } + init { JsonModel.Set(this._rawBodyData, "per_credit_overage_amount", value); } } /// @@ -666,168 +482,107 @@ public double? PerCreditOverageAmount /// public string? PlanID { - get - { - if (!this.BodyProperties.TryGetValue("plan_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["plan_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "plan_id"); } + init { JsonModel.Set(this._rawBodyData, "plan_id", value); } } /// - /// Specifies which version of the plan to subscribe to. If null, the default version - /// will be used. + /// Specifies which version of the plan to subscribe to. If null, the default + /// version will be used. /// public long? PlanVersionNumber { - get - { - if ( - !this.BodyProperties.TryGetValue( - "plan_version_number", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["plan_version_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "plan_version_number"); } + init { JsonModel.Set(this._rawBodyData, "plan_version_number", value); } } /// /// Optionally provide a list of overrides for prices on the plan /// - public Generic::List? PriceOverrides + [System::Obsolete("deprecated")] + public IReadOnlyList? PriceOverrides { get { - if (!this.BodyProperties.TryGetValue("price_overrides", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.BodyProperties["price_overrides"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "price_overrides" + ); } + init { JsonModel.Set(this._rawBodyData, "price_overrides", value); } } /// - /// Plan adjustments to be removed from the subscription. (Only available for accounts - /// that have migrated off of legacy subscription overrides) + /// Plan adjustments to be removed from the subscription. (Only available for + /// accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? RemoveAdjustments + public IReadOnlyList? RemoveAdjustments { get { - if ( - !this.BodyProperties.TryGetValue( - "remove_adjustments", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["remove_adjustments"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "remove_adjustments" ); } + init { JsonModel.Set(this._rawBodyData, "remove_adjustments", value); } } /// /// Plan prices to be removed from the subscription. (Only available for accounts /// that have migrated off of legacy subscription overrides) /// - public Generic::List? RemovePrices + public IReadOnlyList? RemovePrices { get { - if (!this.BodyProperties.TryGetValue("remove_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["remove_prices"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>(this.RawBodyData, "remove_prices"); } + init { JsonModel.Set(this._rawBodyData, "remove_prices", value); } } /// /// Plan adjustments to be replaced with additional adjustments on the subscription. /// (Only available for accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? ReplaceAdjustments + public IReadOnlyList? ReplaceAdjustments { get { - if ( - !this.BodyProperties.TryGetValue( - "replace_adjustments", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["replace_adjustments"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawBodyData, + "replace_adjustments" ); } + init { JsonModel.Set(this._rawBodyData, "replace_adjustments", value); } } /// /// Plan prices to be replaced with additional prices on the subscription. (Only /// available for accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? ReplacePrices + public IReadOnlyList? ReplacePrices { get { - if (!this.BodyProperties.TryGetValue("replace_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "replace_prices" ); } - set - { - this.BodyProperties["replace_prices"] = Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawBodyData, "replace_prices", value); } } - public System::DateTime? StartDate + public System::DateTimeOffset? StartDate { get { - if (!this.BodyProperties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "start_date" + ); } - set { this.BodyProperties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "start_date", value); } } /// @@ -836,80 +591,16421 @@ public long? PlanVersionNumber /// will be skipped. /// public long? TrialDurationDays + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "trial_duration_days"); } + init { JsonModel.Set(this._rawBodyData, "trial_duration_days", value); } + } + + /// + /// A list of customer IDs whose usage events will be aggregated and billed under + /// this subscription. By default, a subscription only considers usage events + /// associated with its attached customer's customer_id. When usage_customer_ids + /// is provided, the subscription includes usage events from the specified customers + /// only. Provided usage_customer_ids must be either the customer for this subscription + /// itself, or any of that customer's children. + /// + public IReadOnlyList? UsageCustomerIDs { get { - if ( - !this.BodyProperties.TryGetValue( - "trial_duration_days", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass>(this.RawBodyData, "usage_customer_ids"); + } + init { JsonModel.Set(this._rawBodyData, "usage_customer_ids", value); } + } + + public SubscriptionCreateParams() { } + + public SubscriptionCreateParams(SubscriptionCreateParams subscriptionCreateParams) + : base(subscriptionCreateParams) + { + this._rawBodyData = [.. subscriptionCreateParams._rawBodyData]; + } + + public SubscriptionCreateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionCreateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionCreateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/subscriptions") + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } - return Json::JsonSerializer.Deserialize(element); + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } - set + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AddAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the subscription. + /// + public required global::Orb.Models.Subscriptions.Adjustment Adjustment + { + get { - this.BodyProperties["trial_duration_days"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" ); } + init { JsonModel.Set(this._rawData, "adjustment", value); } } /// - /// A list of customer IDs whose usage events will be aggregated and billed under - /// this subscription. By default, a subscription only considers usage events associated - /// with its attached customer's customer_id. When usage_customer_ids is provided, - /// the subscription includes usage events from the specified customers only. Provided - /// usage_customer_ids must be either the customer for this subscription itself, - /// or any of that customer's children. + /// The end date of the adjustment interval. This is the date that the adjustment + /// will stop affecting prices on the subscription. /// - public Generic::List? UsageCustomerIDs + public System::DateTimeOffset? EndDate { get { - if ( - !this.BodyProperties.TryGetValue( - "usage_customer_ids", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// The phase to add this adjustment to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// The start date of the adjustment interval. This is the date that the adjustment + /// will start affecting prices on the subscription. If null, the adjustment will + /// start when the phase or subscription starts. + /// + public System::DateTimeOffset? StartDate + { + get { - this.BodyProperties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableStruct(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } } - public override System::Uri Url(Orb::IOrbClient client) + /// + public override void Validate() { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/subscriptions") - { - Query = this.QueryString(client), - }.Uri; + this.Adjustment.Validate(); + _ = this.EndDate; + _ = this.PlanPhaseOrder; + _ = this.StartDate; } - public Http::StringContent BodyContent() + public AddAdjustment() { } + + public AddAdjustment(AddAdjustment addAdjustment) + : base(addAdjustment) { } + + public AddAdjustment(IReadOnlyDictionary rawData) { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AddAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AddAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public AddAdjustment(global::Orb.Models.Subscriptions.Adjustment adjustment) + : this() + { + this.Adjustment = adjustment; + } +} + +class AddAdjustmentFromRaw : IFromRawJson +{ + /// + public AddAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + AddAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the subscription. +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.AdjustmentConverter))] +public record class Adjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public string? Currency { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public Adjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Adjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Adjustment"), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.Adjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Adjustment( + NewUsageDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Adjustment( + NewAmountDiscount value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Adjustment(NewMinimum value) => + new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Adjustment(NewMaximum value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Adjustment"); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Subscriptions.Adjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class AdjustmentConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.Adjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.Adjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.Adjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class AddPrice : JsonModel +{ + /// + /// The definition of a new allocation price to create and add to the subscription. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for + /// this price. + /// + [System::Obsolete("deprecated")] + public IReadOnlyList? Discounts + { + get + { + return JsonModel.GetNullableClass>(this.RawData, "discounts"); + } + init { JsonModel.Set(this._rawData, "discounts", value); } + } + + /// + /// The end date of the price interval. This is the date that the price will stop + /// billing on the subscription. If null, billing will end when the phase or subscription ends. + /// + public System::DateTimeOffset? EndDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "end_date"); + } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// The external price id of the price to add to the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount + /// for this price. + /// + [System::Obsolete("deprecated")] + public string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount + /// for this price. + /// + [System::Obsolete("deprecated")] + public string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The phase to add this price to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New subscription price request body params. + /// + public global::Orb.Models.Subscriptions.Price? Price + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "price" + ); + } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// The id of the price to add to the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + /// The start date of the price interval. This is the date that the price will + /// start billing on the subscription. If null, billing will start when the phase + /// or subscription starts. + /// + public System::DateTimeOffset? StartDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "start_date"); + } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + public override void Validate() + { + this.AllocationPrice?.Validate(); + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + _ = this.EndDate; + _ = this.ExternalPriceID; + _ = this.MaximumAmount; + _ = this.MinimumAmount; + _ = this.PlanPhaseOrder; + this.Price?.Validate(); + _ = this.PriceID; + _ = this.StartDate; + } + + public AddPrice() { } + + public AddPrice(AddPrice addPrice) + : base(addPrice) { } + + public AddPrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AddPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static AddPrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AddPriceFromRaw : IFromRawJson +{ + /// + public AddPrice FromRawUnchecked(IReadOnlyDictionary rawData) => + AddPrice.FromRawUnchecked(rawData); +} + +/// +/// New subscription price request body params. +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.PriceConverter))] +public record class Price +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ItemID, + newSubscriptionTiered: (x) => x.ItemID, + newSubscriptionBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newSubscriptionPackage: (x) => x.ItemID, + newSubscriptionMatrix: (x) => x.ItemID, + newSubscriptionThresholdTotalAmount: (x) => x.ItemID, + newSubscriptionTieredPackage: (x) => x.ItemID, + newSubscriptionTieredWithMinimum: (x) => x.ItemID, + newSubscriptionGroupedTiered: (x) => x.ItemID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ItemID, + newSubscriptionPackageWithAllocation: (x) => x.ItemID, + newSubscriptionUnitWithPercent: (x) => x.ItemID, + newSubscriptionMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newSubscriptionUnitWithProration: (x) => x.ItemID, + newSubscriptionGroupedAllocation: (x) => x.ItemID, + newSubscriptionBulkWithProration: (x) => x.ItemID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ItemID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newSubscriptionMatrixWithDisplayName: (x) => x.ItemID, + newSubscriptionGroupedTieredPackage: (x) => x.ItemID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ItemID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ItemID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ItemID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newSubscriptionMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Name, + newSubscriptionTiered: (x) => x.Name, + newSubscriptionBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newSubscriptionPackage: (x) => x.Name, + newSubscriptionMatrix: (x) => x.Name, + newSubscriptionThresholdTotalAmount: (x) => x.Name, + newSubscriptionTieredPackage: (x) => x.Name, + newSubscriptionTieredWithMinimum: (x) => x.Name, + newSubscriptionGroupedTiered: (x) => x.Name, + newSubscriptionTieredPackageWithMinimum: (x) => x.Name, + newSubscriptionPackageWithAllocation: (x) => x.Name, + newSubscriptionUnitWithPercent: (x) => x.Name, + newSubscriptionMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newSubscriptionUnitWithProration: (x) => x.Name, + newSubscriptionGroupedAllocation: (x) => x.Name, + newSubscriptionBulkWithProration: (x) => x.Name, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Name, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newSubscriptionMatrixWithDisplayName: (x) => x.Name, + newSubscriptionGroupedTieredPackage: (x) => x.Name, + newSubscriptionMaxGroupTieredPackage: (x) => x.Name, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Name, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Name, + newSubscriptionCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newSubscriptionMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillableMetricID, + newSubscriptionTiered: (x) => x.BillableMetricID, + newSubscriptionBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newSubscriptionPackage: (x) => x.BillableMetricID, + newSubscriptionMatrix: (x) => x.BillableMetricID, + newSubscriptionThresholdTotalAmount: (x) => x.BillableMetricID, + newSubscriptionTieredPackage: (x) => x.BillableMetricID, + newSubscriptionTieredWithMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedTiered: (x) => x.BillableMetricID, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillableMetricID, + newSubscriptionPackageWithAllocation: (x) => x.BillableMetricID, + newSubscriptionUnitWithPercent: (x) => x.BillableMetricID, + newSubscriptionMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newSubscriptionUnitWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionBulkWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newSubscriptionMatrixWithDisplayName: (x) => x.BillableMetricID, + newSubscriptionGroupedTieredPackage: (x) => x.BillableMetricID, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BilledInAdvance, + newSubscriptionTiered: (x) => x.BilledInAdvance, + newSubscriptionBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newSubscriptionPackage: (x) => x.BilledInAdvance, + newSubscriptionMatrix: (x) => x.BilledInAdvance, + newSubscriptionThresholdTotalAmount: (x) => x.BilledInAdvance, + newSubscriptionTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionTieredWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedTiered: (x) => x.BilledInAdvance, + newSubscriptionTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionPackageWithAllocation: (x) => x.BilledInAdvance, + newSubscriptionUnitWithPercent: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newSubscriptionUnitWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionBulkWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithDisplayName: (x) => x.BilledInAdvance, + newSubscriptionGroupedTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newSubscriptionCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillingCycleConfiguration, + newSubscriptionTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newSubscriptionPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrix: (x) => x.BillingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ConversionRate, + newSubscriptionTiered: (x) => x.ConversionRate, + newSubscriptionBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newSubscriptionPackage: (x) => x.ConversionRate, + newSubscriptionMatrix: (x) => x.ConversionRate, + newSubscriptionThresholdTotalAmount: (x) => x.ConversionRate, + newSubscriptionTieredPackage: (x) => x.ConversionRate, + newSubscriptionTieredWithMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedTiered: (x) => x.ConversionRate, + newSubscriptionTieredPackageWithMinimum: (x) => x.ConversionRate, + newSubscriptionPackageWithAllocation: (x) => x.ConversionRate, + newSubscriptionUnitWithPercent: (x) => x.ConversionRate, + newSubscriptionMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newSubscriptionUnitWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionBulkWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newSubscriptionMatrixWithDisplayName: (x) => x.ConversionRate, + newSubscriptionGroupedTieredPackage: (x) => x.ConversionRate, + newSubscriptionMaxGroupTieredPackage: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newSubscriptionCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Currency, + newSubscriptionTiered: (x) => x.Currency, + newSubscriptionBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newSubscriptionPackage: (x) => x.Currency, + newSubscriptionMatrix: (x) => x.Currency, + newSubscriptionThresholdTotalAmount: (x) => x.Currency, + newSubscriptionTieredPackage: (x) => x.Currency, + newSubscriptionTieredWithMinimum: (x) => x.Currency, + newSubscriptionGroupedTiered: (x) => x.Currency, + newSubscriptionTieredPackageWithMinimum: (x) => x.Currency, + newSubscriptionPackageWithAllocation: (x) => x.Currency, + newSubscriptionUnitWithPercent: (x) => x.Currency, + newSubscriptionMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newSubscriptionUnitWithProration: (x) => x.Currency, + newSubscriptionGroupedAllocation: (x) => x.Currency, + newSubscriptionBulkWithProration: (x) => x.Currency, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Currency, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newSubscriptionMatrixWithDisplayName: (x) => x.Currency, + newSubscriptionGroupedTieredPackage: (x) => x.Currency, + newSubscriptionMaxGroupTieredPackage: (x) => x.Currency, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Currency, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Currency, + newSubscriptionCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newSubscriptionMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrix: (x) => x.DimensionalPriceConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ExternalPriceID, + newSubscriptionTiered: (x) => x.ExternalPriceID, + newSubscriptionBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newSubscriptionPackage: (x) => x.ExternalPriceID, + newSubscriptionMatrix: (x) => x.ExternalPriceID, + newSubscriptionThresholdTotalAmount: (x) => x.ExternalPriceID, + newSubscriptionTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionTieredWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedTiered: (x) => x.ExternalPriceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionPackageWithAllocation: (x) => x.ExternalPriceID, + newSubscriptionUnitWithPercent: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newSubscriptionUnitWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionBulkWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ExternalPriceID, + newSubscriptionGroupedTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newSubscriptionUnit: (x) => x.FixedPriceQuantity, + newSubscriptionTiered: (x) => x.FixedPriceQuantity, + newSubscriptionBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newSubscriptionPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMatrix: (x) => x.FixedPriceQuantity, + newSubscriptionThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionTieredWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTiered: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionPackageWithAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithPercent: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionBulkWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newSubscriptionCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoiceGroupingKey, + newSubscriptionTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newSubscriptionPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrix: (x) => x.InvoiceGroupingKey, + newSubscriptionThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithPercent: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionBulkWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrix: (x) => x.InvoicingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.InvoicingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ReferenceID, + newSubscriptionTiered: (x) => x.ReferenceID, + newSubscriptionBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newSubscriptionPackage: (x) => x.ReferenceID, + newSubscriptionMatrix: (x) => x.ReferenceID, + newSubscriptionThresholdTotalAmount: (x) => x.ReferenceID, + newSubscriptionTieredPackage: (x) => x.ReferenceID, + newSubscriptionTieredWithMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedTiered: (x) => x.ReferenceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ReferenceID, + newSubscriptionPackageWithAllocation: (x) => x.ReferenceID, + newSubscriptionUnitWithPercent: (x) => x.ReferenceID, + newSubscriptionMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newSubscriptionUnitWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionBulkWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ReferenceID, + newSubscriptionGroupedTieredPackage: (x) => x.ReferenceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public Price(NewSubscriptionUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Subscriptions.BulkWithFilters value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Subscriptions.TieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + NewSubscriptionScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price( + NewSubscriptionScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price( + global::Orb.Models.Subscriptions.CumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public Price(NewSubscriptionMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Subscriptions.Percent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(global::Orb.Models.Subscriptions.EventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Price(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnit(out var value)) { + /// // `value` is of type `NewSubscriptionUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnit([NotNullWhen(true)] out NewSubscriptionUnitPrice? value) + { + value = this.Value as NewSubscriptionUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTiered(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTiered( + [NotNullWhen(true)] out NewSubscriptionTieredPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulk(out var value)) { + /// // `value` is of type `NewSubscriptionBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulk([NotNullWhen(true)] out NewSubscriptionBulkPrice? value) + { + value = this.Value as NewSubscriptionBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `global::Orb.Models.Subscriptions.BulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out global::Orb.Models.Subscriptions.BulkWithFilters? value + ) + { + value = this.Value as global::Orb.Models.Subscriptions.BulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackage(out var value)) { + /// // `value` is of type `NewSubscriptionPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackage( + [NotNullWhen(true)] out NewSubscriptionPackagePrice? value + ) + { + value = this.Value as NewSubscriptionPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrix(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrix( + [NotNullWhen(true)] out NewSubscriptionMatrixPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewSubscriptionThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionThresholdTotalAmount( + [NotNullWhen(true)] out NewSubscriptionThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewSubscriptionThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackage( + [NotNullWhen(true)] out NewSubscriptionTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTiered(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTiered( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackageWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackageWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackageWithAllocation( + [NotNullWhen(true)] out NewSubscriptionPackageWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithPercent(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithPercent( + [NotNullWhen(true)] out NewSubscriptionUnitWithPercentPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithAllocation( + [NotNullWhen(true)] out NewSubscriptionMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `global::Orb.Models.Subscriptions.TieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] out global::Orb.Models.Subscriptions.TieredWithProration? value + ) + { + value = this.Value as global::Orb.Models.Subscriptions.TieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithProration( + [NotNullWhen(true)] out NewSubscriptionUnitWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedAllocation( + [NotNullWhen(true)] out NewSubscriptionGroupedAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulkWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulkWithProration( + [NotNullWhen(true)] out NewSubscriptionBulkWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds? value + ) + { + value = this.Value as global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithDisplayName( + [NotNullWhen(true)] out NewSubscriptionMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTieredPackage( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMaxGroupTieredPackage( + [NotNullWhen(true)] out NewSubscriptionMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewSubscriptionCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionCumulativeGroupedBulk( + [NotNullWhen(true)] out NewSubscriptionCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewSubscriptionCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `global::Orb.Models.Subscriptions.CumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out global::Orb.Models.Subscriptions.CumulativeGroupedAllocation? value + ) + { + value = this.Value as global::Orb.Models.Subscriptions.CumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMinimumComposite(out var value)) { + /// // `value` is of type `NewSubscriptionMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMinimumComposite( + [NotNullWhen(true)] out NewSubscriptionMinimumCompositePrice? value + ) + { + value = this.Value as NewSubscriptionMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `global::Orb.Models.Subscriptions.Percent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent( + [NotNullWhen(true)] out global::Orb.Models.Subscriptions.Percent? value + ) + { + value = this.Value as global::Orb.Models.Subscriptions.Percent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `global::Orb.Models.Subscriptions.EventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] out global::Orb.Models.Subscriptions.EventOutput? value + ) + { + value = this.Value as global::Orb.Models.Subscriptions.EventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.BulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.TieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.CumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Subscriptions.Percent value) => {...}, + /// (global::Orb.Models.Subscriptions.EventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newSubscriptionUnit, + System::Action newSubscriptionTiered, + System::Action newSubscriptionBulk, + System::Action bulkWithFilters, + System::Action newSubscriptionPackage, + System::Action newSubscriptionMatrix, + System::Action newSubscriptionThresholdTotalAmount, + System::Action newSubscriptionTieredPackage, + System::Action newSubscriptionTieredWithMinimum, + System::Action newSubscriptionGroupedTiered, + System::Action newSubscriptionTieredPackageWithMinimum, + System::Action newSubscriptionPackageWithAllocation, + System::Action newSubscriptionUnitWithPercent, + System::Action newSubscriptionMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newSubscriptionUnitWithProration, + System::Action newSubscriptionGroupedAllocation, + System::Action newSubscriptionBulkWithProration, + System::Action newSubscriptionGroupedWithProratedMinimum, + System::Action newSubscriptionGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newSubscriptionMatrixWithDisplayName, + System::Action newSubscriptionGroupedTieredPackage, + System::Action newSubscriptionMaxGroupTieredPackage, + System::Action newSubscriptionScalableMatrixWithUnitPricing, + System::Action newSubscriptionScalableMatrixWithTieredPricing, + System::Action newSubscriptionCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newSubscriptionMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewSubscriptionUnitPrice value: + newSubscriptionUnit(value); + break; + case NewSubscriptionTieredPrice value: + newSubscriptionTiered(value); + break; + case NewSubscriptionBulkPrice value: + newSubscriptionBulk(value); + break; + case global::Orb.Models.Subscriptions.BulkWithFilters value: + bulkWithFilters(value); + break; + case NewSubscriptionPackagePrice value: + newSubscriptionPackage(value); + break; + case NewSubscriptionMatrixPrice value: + newSubscriptionMatrix(value); + break; + case NewSubscriptionThresholdTotalAmountPrice value: + newSubscriptionThresholdTotalAmount(value); + break; + case NewSubscriptionTieredPackagePrice value: + newSubscriptionTieredPackage(value); + break; + case NewSubscriptionTieredWithMinimumPrice value: + newSubscriptionTieredWithMinimum(value); + break; + case NewSubscriptionGroupedTieredPrice value: + newSubscriptionGroupedTiered(value); + break; + case NewSubscriptionTieredPackageWithMinimumPrice value: + newSubscriptionTieredPackageWithMinimum(value); + break; + case NewSubscriptionPackageWithAllocationPrice value: + newSubscriptionPackageWithAllocation(value); + break; + case NewSubscriptionUnitWithPercentPrice value: + newSubscriptionUnitWithPercent(value); + break; + case NewSubscriptionMatrixWithAllocationPrice value: + newSubscriptionMatrixWithAllocation(value); + break; + case global::Orb.Models.Subscriptions.TieredWithProration value: + tieredWithProration(value); + break; + case NewSubscriptionUnitWithProrationPrice value: + newSubscriptionUnitWithProration(value); + break; + case NewSubscriptionGroupedAllocationPrice value: + newSubscriptionGroupedAllocation(value); + break; + case NewSubscriptionBulkWithProrationPrice value: + newSubscriptionBulkWithProration(value); + break; + case NewSubscriptionGroupedWithProratedMinimumPrice value: + newSubscriptionGroupedWithProratedMinimum(value); + break; + case NewSubscriptionGroupedWithMeteredMinimumPrice value: + newSubscriptionGroupedWithMeteredMinimum(value); + break; + case global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewSubscriptionMatrixWithDisplayNamePrice value: + newSubscriptionMatrixWithDisplayName(value); + break; + case NewSubscriptionGroupedTieredPackagePrice value: + newSubscriptionGroupedTieredPackage(value); + break; + case NewSubscriptionMaxGroupTieredPackagePrice value: + newSubscriptionMaxGroupTieredPackage(value); + break; + case NewSubscriptionScalableMatrixWithUnitPricingPrice value: + newSubscriptionScalableMatrixWithUnitPricing(value); + break; + case NewSubscriptionScalableMatrixWithTieredPricingPrice value: + newSubscriptionScalableMatrixWithTieredPricing(value); + break; + case NewSubscriptionCumulativeGroupedBulkPrice value: + newSubscriptionCumulativeGroupedBulk(value); + break; + case global::Orb.Models.Subscriptions.CumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewSubscriptionMinimumCompositePrice value: + newSubscriptionMinimumComposite(value); + break; + case global::Orb.Models.Subscriptions.Percent value: + percent(value); + break; + case global::Orb.Models.Subscriptions.EventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.BulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.TieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (global::Orb.Models.Subscriptions.CumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (global::Orb.Models.Subscriptions.Percent value) => {...}, + /// (global::Orb.Models.Subscriptions.EventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newSubscriptionUnit, + System::Func newSubscriptionTiered, + System::Func newSubscriptionBulk, + System::Func bulkWithFilters, + System::Func newSubscriptionPackage, + System::Func newSubscriptionMatrix, + System::Func< + NewSubscriptionThresholdTotalAmountPrice, + T + > newSubscriptionThresholdTotalAmount, + System::Func newSubscriptionTieredPackage, + System::Func newSubscriptionTieredWithMinimum, + System::Func newSubscriptionGroupedTiered, + System::Func< + NewSubscriptionTieredPackageWithMinimumPrice, + T + > newSubscriptionTieredPackageWithMinimum, + System::Func< + NewSubscriptionPackageWithAllocationPrice, + T + > newSubscriptionPackageWithAllocation, + System::Func newSubscriptionUnitWithPercent, + System::Func< + NewSubscriptionMatrixWithAllocationPrice, + T + > newSubscriptionMatrixWithAllocation, + System::Func tieredWithProration, + System::Func newSubscriptionUnitWithProration, + System::Func newSubscriptionGroupedAllocation, + System::Func newSubscriptionBulkWithProration, + System::Func< + NewSubscriptionGroupedWithProratedMinimumPrice, + T + > newSubscriptionGroupedWithProratedMinimum, + System::Func< + NewSubscriptionGroupedWithMeteredMinimumPrice, + T + > newSubscriptionGroupedWithMeteredMinimum, + System::Func< + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func< + NewSubscriptionMatrixWithDisplayNamePrice, + T + > newSubscriptionMatrixWithDisplayName, + System::Func< + NewSubscriptionGroupedTieredPackagePrice, + T + > newSubscriptionGroupedTieredPackage, + System::Func< + NewSubscriptionMaxGroupTieredPackagePrice, + T + > newSubscriptionMaxGroupTieredPackage, + System::Func< + NewSubscriptionScalableMatrixWithUnitPricingPrice, + T + > newSubscriptionScalableMatrixWithUnitPricing, + System::Func< + NewSubscriptionScalableMatrixWithTieredPricingPrice, + T + > newSubscriptionScalableMatrixWithTieredPricing, + System::Func< + NewSubscriptionCumulativeGroupedBulkPrice, + T + > newSubscriptionCumulativeGroupedBulk, + System::Func< + global::Orb.Models.Subscriptions.CumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newSubscriptionMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewSubscriptionUnitPrice value => newSubscriptionUnit(value), + NewSubscriptionTieredPrice value => newSubscriptionTiered(value), + NewSubscriptionBulkPrice value => newSubscriptionBulk(value), + global::Orb.Models.Subscriptions.BulkWithFilters value => bulkWithFilters(value), + NewSubscriptionPackagePrice value => newSubscriptionPackage(value), + NewSubscriptionMatrixPrice value => newSubscriptionMatrix(value), + NewSubscriptionThresholdTotalAmountPrice value => newSubscriptionThresholdTotalAmount( + value + ), + NewSubscriptionTieredPackagePrice value => newSubscriptionTieredPackage(value), + NewSubscriptionTieredWithMinimumPrice value => newSubscriptionTieredWithMinimum(value), + NewSubscriptionGroupedTieredPrice value => newSubscriptionGroupedTiered(value), + NewSubscriptionTieredPackageWithMinimumPrice value => + newSubscriptionTieredPackageWithMinimum(value), + NewSubscriptionPackageWithAllocationPrice value => newSubscriptionPackageWithAllocation( + value + ), + NewSubscriptionUnitWithPercentPrice value => newSubscriptionUnitWithPercent(value), + NewSubscriptionMatrixWithAllocationPrice value => newSubscriptionMatrixWithAllocation( + value + ), + global::Orb.Models.Subscriptions.TieredWithProration value => tieredWithProration( + value + ), + NewSubscriptionUnitWithProrationPrice value => newSubscriptionUnitWithProration(value), + NewSubscriptionGroupedAllocationPrice value => newSubscriptionGroupedAllocation(value), + NewSubscriptionBulkWithProrationPrice value => newSubscriptionBulkWithProration(value), + NewSubscriptionGroupedWithProratedMinimumPrice value => + newSubscriptionGroupedWithProratedMinimum(value), + NewSubscriptionGroupedWithMeteredMinimumPrice value => + newSubscriptionGroupedWithMeteredMinimum(value), + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewSubscriptionMatrixWithDisplayNamePrice value => newSubscriptionMatrixWithDisplayName( + value + ), + NewSubscriptionGroupedTieredPackagePrice value => newSubscriptionGroupedTieredPackage( + value + ), + NewSubscriptionMaxGroupTieredPackagePrice value => newSubscriptionMaxGroupTieredPackage( + value + ), + NewSubscriptionScalableMatrixWithUnitPricingPrice value => + newSubscriptionScalableMatrixWithUnitPricing(value), + NewSubscriptionScalableMatrixWithTieredPricingPrice value => + newSubscriptionScalableMatrixWithTieredPricing(value), + NewSubscriptionCumulativeGroupedBulkPrice value => newSubscriptionCumulativeGroupedBulk( + value + ), + global::Orb.Models.Subscriptions.CumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewSubscriptionMinimumCompositePrice value => newSubscriptionMinimumComposite(value), + global::Orb.Models.Subscriptions.Percent value => percent(value), + global::Orb.Models.Subscriptions.EventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Price"), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionUnitPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + global::Orb.Models.Subscriptions.BulkWithFilters value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionMatrixPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionGroupedTieredPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionUnitWithPercentPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + global::Orb.Models.Subscriptions.TieredWithProration value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionUnitWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionGroupedAllocationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionBulkWithProrationPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + global::Orb.Models.Subscriptions.CumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + NewSubscriptionMinimumCompositePrice value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + global::Orb.Models.Subscriptions.Percent value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Price( + global::Orb.Models.Subscriptions.EventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Price"); + } + this.Switch( + (newSubscriptionUnit) => newSubscriptionUnit.Validate(), + (newSubscriptionTiered) => newSubscriptionTiered.Validate(), + (newSubscriptionBulk) => newSubscriptionBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newSubscriptionPackage) => newSubscriptionPackage.Validate(), + (newSubscriptionMatrix) => newSubscriptionMatrix.Validate(), + (newSubscriptionThresholdTotalAmount) => newSubscriptionThresholdTotalAmount.Validate(), + (newSubscriptionTieredPackage) => newSubscriptionTieredPackage.Validate(), + (newSubscriptionTieredWithMinimum) => newSubscriptionTieredWithMinimum.Validate(), + (newSubscriptionGroupedTiered) => newSubscriptionGroupedTiered.Validate(), + (newSubscriptionTieredPackageWithMinimum) => + newSubscriptionTieredPackageWithMinimum.Validate(), + (newSubscriptionPackageWithAllocation) => + newSubscriptionPackageWithAllocation.Validate(), + (newSubscriptionUnitWithPercent) => newSubscriptionUnitWithPercent.Validate(), + (newSubscriptionMatrixWithAllocation) => newSubscriptionMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newSubscriptionUnitWithProration) => newSubscriptionUnitWithProration.Validate(), + (newSubscriptionGroupedAllocation) => newSubscriptionGroupedAllocation.Validate(), + (newSubscriptionBulkWithProration) => newSubscriptionBulkWithProration.Validate(), + (newSubscriptionGroupedWithProratedMinimum) => + newSubscriptionGroupedWithProratedMinimum.Validate(), + (newSubscriptionGroupedWithMeteredMinimum) => + newSubscriptionGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newSubscriptionMatrixWithDisplayName) => + newSubscriptionMatrixWithDisplayName.Validate(), + (newSubscriptionGroupedTieredPackage) => newSubscriptionGroupedTieredPackage.Validate(), + (newSubscriptionMaxGroupTieredPackage) => + newSubscriptionMaxGroupTieredPackage.Validate(), + (newSubscriptionScalableMatrixWithUnitPricing) => + newSubscriptionScalableMatrixWithUnitPricing.Validate(), + (newSubscriptionScalableMatrixWithTieredPricing) => + newSubscriptionScalableMatrixWithTieredPricing.Validate(), + (newSubscriptionCumulativeGroupedBulk) => + newSubscriptionCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newSubscriptionMinimumComposite) => newSubscriptionMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Subscriptions.Price? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.Price? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.Price(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.Price? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.BulkWithFilters, + global::Orb.Models.Subscriptions.BulkWithFiltersFromRaw + >) +)] +public sealed record class BulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required global::Orb.Models.Subscriptions.BulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Subscriptions.ConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public BulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public BulkWithFilters(global::Orb.Models.Subscriptions.BulkWithFilters bulkWithFilters) + : base(bulkWithFilters) { } + + public BulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.BulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.BulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.BulkWithFiltersConfig, + global::Orb.Models.Subscriptions.BulkWithFiltersConfigFromRaw + >) +)] +public sealed record class BulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "tiers" + ); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public BulkWithFiltersConfig() { } + + public BulkWithFiltersConfig( + global::Orb.Models.Subscriptions.BulkWithFiltersConfig bulkWithFiltersConfig + ) + : base(bulkWithFiltersConfig) { } + + public BulkWithFiltersConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.BulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.BulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.Filter, + global::Orb.Models.Subscriptions.FilterFromRaw + >) +)] +public sealed record class Filter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public Filter() { } + + public Filter(global::Orb.Models.Subscriptions.Filter filter) + : base(filter) { } + + public Filter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Filter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FilterFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.Filter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.Filter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.Tier, + global::Orb.Models.Subscriptions.TierFromRaw + >) +)] +public sealed record class Tier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public Tier() { } + + public Tier(global::Orb.Models.Subscriptions.Tier tier) + : base(tier) { } + + public Tier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Tier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Tier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class TierFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.Tier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.Tier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.CadenceConverter))] +public enum Cadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CadenceConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.Cadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Subscriptions.Cadence.Annual, + "semi_annual" => global::Orb.Models.Subscriptions.Cadence.SemiAnnual, + "monthly" => global::Orb.Models.Subscriptions.Cadence.Monthly, + "quarterly" => global::Orb.Models.Subscriptions.Cadence.Quarterly, + "one_time" => global::Orb.Models.Subscriptions.Cadence.OneTime, + "custom" => global::Orb.Models.Subscriptions.Cadence.Custom, + _ => (global::Orb.Models.Subscriptions.Cadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.Cadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.Cadence.Annual => "annual", + global::Orb.Models.Subscriptions.Cadence.SemiAnnual => "semi_annual", + global::Orb.Models.Subscriptions.Cadence.Monthly => "monthly", + global::Orb.Models.Subscriptions.Cadence.Quarterly => "quarterly", + global::Orb.Models.Subscriptions.Cadence.OneTime => "one_time", + global::Orb.Models.Subscriptions.Cadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(global::Orb.Models.Subscriptions.ConversionRateConfigConverter))] +public record class ConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ConversionRateConfig(SharedUnitConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(SharedTieredConversionRateConfig value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.ConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.ConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Subscriptions.ConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.ConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.ConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.ConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredWithProration, + global::Orb.Models.Subscriptions.TieredWithProrationFromRaw + >) +)] +public sealed record class TieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Subscriptions.TieredWithProrationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required global::Orb.Models.Subscriptions.TieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public TieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public TieredWithProration( + global::Orb.Models.Subscriptions.TieredWithProration tieredWithProration + ) + : base(tieredWithProration) { } + + public TieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredWithProration.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.TieredWithProrationCadenceConverter))] +public enum TieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class TieredWithProrationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.TieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Subscriptions.TieredWithProrationCadence.Annual, + "semi_annual" => global::Orb.Models.Subscriptions.TieredWithProrationCadence.SemiAnnual, + "monthly" => global::Orb.Models.Subscriptions.TieredWithProrationCadence.Monthly, + "quarterly" => global::Orb.Models.Subscriptions.TieredWithProrationCadence.Quarterly, + "one_time" => global::Orb.Models.Subscriptions.TieredWithProrationCadence.OneTime, + "custom" => global::Orb.Models.Subscriptions.TieredWithProrationCadence.Custom, + _ => (global::Orb.Models.Subscriptions.TieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.TieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.TieredWithProrationCadence.Annual => "annual", + global::Orb.Models.Subscriptions.TieredWithProrationCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Subscriptions.TieredWithProrationCadence.Monthly => "monthly", + global::Orb.Models.Subscriptions.TieredWithProrationCadence.Quarterly => + "quarterly", + global::Orb.Models.Subscriptions.TieredWithProrationCadence.OneTime => "one_time", + global::Orb.Models.Subscriptions.TieredWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredWithProrationConfig, + global::Orb.Models.Subscriptions.TieredWithProrationConfigFromRaw + >) +)] +public sealed record class TieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public TieredWithProrationConfig() { } + + public TieredWithProrationConfig( + global::Orb.Models.Subscriptions.TieredWithProrationConfig tieredWithProrationConfig + ) + : base(tieredWithProrationConfig) { } + + public TieredWithProrationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class TieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.TieredWithProrationConfigTier, + global::Orb.Models.Subscriptions.TieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class TieredWithProrationConfigTier : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public TieredWithProrationConfigTier() { } + + public TieredWithProrationConfigTier( + global::Orb.Models.Subscriptions.TieredWithProrationConfigTier tieredWithProrationConfigTier + ) + : base(tieredWithProrationConfigTier) { } + + public TieredWithProrationConfigTier(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TieredWithProrationConfigTier(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.TieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.TieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfigConverter) +)] +public record class TieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public TieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of TieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.TieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds, + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public GroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public GroupedWithMinMaxThresholds( + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds groupedWithMinMaxThresholds + ) + : base(groupedWithMinMaxThresholds) { } + + public GroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadenceConverter) +)] +public enum GroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class GroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => global::Orb + .Models + .Subscriptions + .GroupedWithMinMaxThresholdsCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Subscriptions + .GroupedWithMinMaxThresholdsCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Subscriptions + .GroupedWithMinMaxThresholdsCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Subscriptions + .GroupedWithMinMaxThresholdsCadence + .OneTime, + "custom" => global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.Custom, + _ => (global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.Annual => + "annual", + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.Monthly => + "monthly", + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.Quarterly => + "quarterly", + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.OneTime => + "one_time", + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfig, + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class GroupedWithMinMaxThresholdsConfig : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public GroupedWithMinMaxThresholdsConfig() { } + + public GroupedWithMinMaxThresholdsConfig( + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfig groupedWithMinMaxThresholdsConfig + ) + : base(groupedWithMinMaxThresholdsConfig) { } + + public GroupedWithMinMaxThresholdsConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedWithMinMaxThresholdsConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class GroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public GroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of GroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class GroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.GroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.CumulativeGroupedAllocation, + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public CumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public CumulativeGroupedAllocation( + global::Orb.Models.Subscriptions.CumulativeGroupedAllocation cumulativeGroupedAllocation + ) + : base(cumulativeGroupedAllocation) { } + + public CumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.CumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.CumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadenceConverter) +)] +public enum CumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class CumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.Annual, + "semi_annual" => global::Orb + .Models + .Subscriptions + .CumulativeGroupedAllocationCadence + .SemiAnnual, + "monthly" => global::Orb + .Models + .Subscriptions + .CumulativeGroupedAllocationCadence + .Monthly, + "quarterly" => global::Orb + .Models + .Subscriptions + .CumulativeGroupedAllocationCadence + .Quarterly, + "one_time" => global::Orb + .Models + .Subscriptions + .CumulativeGroupedAllocationCadence + .OneTime, + "custom" => global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.Custom, + _ => (global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.Annual => + "annual", + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.Monthly => + "monthly", + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.Quarterly => + "quarterly", + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.OneTime => + "one_time", + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfig, + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class CumulativeGroupedAllocationConfig : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public CumulativeGroupedAllocationConfig() { } + + public CumulativeGroupedAllocationConfig( + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfig cumulativeGroupedAllocationConfig + ) + : base(cumulativeGroupedAllocationConfig) { } + + public CumulativeGroupedAllocationConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + CumulativeGroupedAllocationConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class CumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class CumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public CumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of CumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class CumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.CumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.Percent, + global::Orb.Models.Subscriptions.PercentFromRaw + >) +)] +public sealed record class Percent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required global::Orb.Models.Subscriptions.PercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Subscriptions.PercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public Percent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public Percent(global::Orb.Models.Subscriptions.Percent percent) + : base(percent) { } + + public Percent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PercentFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.Percent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.Percent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.PercentCadenceConverter))] +public enum PercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PercentCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.PercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Subscriptions.PercentCadence.Annual, + "semi_annual" => global::Orb.Models.Subscriptions.PercentCadence.SemiAnnual, + "monthly" => global::Orb.Models.Subscriptions.PercentCadence.Monthly, + "quarterly" => global::Orb.Models.Subscriptions.PercentCadence.Quarterly, + "one_time" => global::Orb.Models.Subscriptions.PercentCadence.OneTime, + "custom" => global::Orb.Models.Subscriptions.PercentCadence.Custom, + _ => (global::Orb.Models.Subscriptions.PercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.PercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.PercentCadence.Annual => "annual", + global::Orb.Models.Subscriptions.PercentCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Subscriptions.PercentCadence.Monthly => "monthly", + global::Orb.Models.Subscriptions.PercentCadence.Quarterly => "quarterly", + global::Orb.Models.Subscriptions.PercentCadence.OneTime => "one_time", + global::Orb.Models.Subscriptions.PercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.PercentConfig, + global::Orb.Models.Subscriptions.PercentConfigFromRaw + >) +)] +public sealed record class PercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PercentConfig() { } + + public PercentConfig(global::Orb.Models.Subscriptions.PercentConfig percentConfig) + : base(percentConfig) { } + + public PercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PercentConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.PercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.PercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Subscriptions.PercentConversionRateConfigConverter))] +public record class PercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.PercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.PercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(global::Orb.Models.Subscriptions.PercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PercentConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.PercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.PercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.PercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.EventOutput, + global::Orb.Models.Subscriptions.EventOutputFromRaw + >) +)] +public sealed record class EventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required global::Orb.Models.Subscriptions.EventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public global::Orb.Models.Subscriptions.EventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public EventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public EventOutput(global::Orb.Models.Subscriptions.EventOutput eventOutput) + : base(eventOutput) { } + + public EventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EventOutputFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.EventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.EventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(global::Orb.Models.Subscriptions.EventOutputCadenceConverter))] +public enum EventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class EventOutputCadenceConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.EventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => global::Orb.Models.Subscriptions.EventOutputCadence.Annual, + "semi_annual" => global::Orb.Models.Subscriptions.EventOutputCadence.SemiAnnual, + "monthly" => global::Orb.Models.Subscriptions.EventOutputCadence.Monthly, + "quarterly" => global::Orb.Models.Subscriptions.EventOutputCadence.Quarterly, + "one_time" => global::Orb.Models.Subscriptions.EventOutputCadence.OneTime, + "custom" => global::Orb.Models.Subscriptions.EventOutputCadence.Custom, + _ => (global::Orb.Models.Subscriptions.EventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.EventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.EventOutputCadence.Annual => "annual", + global::Orb.Models.Subscriptions.EventOutputCadence.SemiAnnual => "semi_annual", + global::Orb.Models.Subscriptions.EventOutputCadence.Monthly => "monthly", + global::Orb.Models.Subscriptions.EventOutputCadence.Quarterly => "quarterly", + global::Orb.Models.Subscriptions.EventOutputCadence.OneTime => "one_time", + global::Orb.Models.Subscriptions.EventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.EventOutputConfig, + global::Orb.Models.Subscriptions.EventOutputConfigFromRaw + >) +)] +public sealed record class EventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public EventOutputConfig() { } + + public EventOutputConfig(global::Orb.Models.Subscriptions.EventOutputConfig eventOutputConfig) + : base(eventOutputConfig) { } + + public EventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class EventOutputConfigFromRaw : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.EventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.EventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(global::Orb.Models.Subscriptions.EventOutputConversionRateConfigConverter))] +public record class EventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.EventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator global::Orb.Models.Subscriptions.EventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + global::Orb.Models.Subscriptions.EventOutputConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EventOutputConversionRateConfigConverter + : JsonConverter +{ + public override global::Orb.Models.Subscriptions.EventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.EventOutputConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.EventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[System::Obsolete("deprecated")] +[JsonConverter(typeof(ExternalMarketplaceConverter))] +public enum ExternalMarketplace +{ + Google, + Aws, + Azure, +} + +sealed class ExternalMarketplaceConverter : JsonConverter +{ + public override ExternalMarketplace Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "google" => ExternalMarketplace.Google, + "aws" => ExternalMarketplace.Aws, + "azure" => ExternalMarketplace.Azure, + _ => (ExternalMarketplace)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExternalMarketplace value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ExternalMarketplace.Google => "google", + ExternalMarketplace.Aws => "aws", + ExternalMarketplace.Azure => "azure", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class RemoveAdjustment : JsonModel +{ + /// + /// The id of the adjustment to remove on the subscription. + /// + public required string AdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment_id"); } + init { JsonModel.Set(this._rawData, "adjustment_id", value); } + } + + /// + public override void Validate() + { + _ = this.AdjustmentID; + } + + public RemoveAdjustment() { } + + public RemoveAdjustment(RemoveAdjustment removeAdjustment) + : base(removeAdjustment) { } + + public RemoveAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + RemoveAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static RemoveAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public RemoveAdjustment(string adjustmentID) + : this() + { + this.AdjustmentID = adjustmentID; + } +} + +class RemoveAdjustmentFromRaw : IFromRawJson +{ + /// + public RemoveAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + RemoveAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class RemovePrice : JsonModel +{ + /// + /// The external price id of the price to remove on the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// The id of the price to remove on the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.ExternalPriceID; + _ = this.PriceID; + } + + public RemovePrice() { } + + public RemovePrice(RemovePrice removePrice) + : base(removePrice) { } + + public RemovePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + RemovePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static RemovePrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class RemovePriceFromRaw : IFromRawJson +{ + /// + public RemovePrice FromRawUnchecked(IReadOnlyDictionary rawData) => + RemovePrice.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ReplaceAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the subscription. + /// + public required ReplaceAdjustmentAdjustment Adjustment + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" + ); + } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The id of the adjustment on the plan to replace in the subscription. + /// + public required string ReplacesAdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.ReplacesAdjustmentID; + } + + public ReplaceAdjustment() { } + + public ReplaceAdjustment(ReplaceAdjustment replaceAdjustment) + : base(replaceAdjustment) { } + + public ReplaceAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplaceAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplaceAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplaceAdjustmentFromRaw : IFromRawJson +{ + /// + public ReplaceAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + ReplaceAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the subscription. +/// +[JsonConverter(typeof(ReplaceAdjustmentAdjustmentConverter))] +public record class ReplaceAdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public ReplaceAdjustmentAdjustment(NewPercentageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewUsageDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewAmountDiscount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewMinimum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(NewMaximum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplaceAdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ), + }; + } + + public static implicit operator ReplaceAdjustmentAdjustment(NewPercentageDiscount value) => + new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewUsageDiscount value) => + new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewAmountDiscount value) => + new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewMinimum value) => new(value); + + public static implicit operator ReplaceAdjustmentAdjustment(NewMaximum value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplaceAdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(ReplaceAdjustmentAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplaceAdjustmentAdjustmentConverter : JsonConverter +{ + public override ReplaceAdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplaceAdjustmentAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplaceAdjustmentAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class ReplacePrice : JsonModel +{ + /// + /// The id of the price on the plan to replace in the subscription. + /// + public required string ReplacesPriceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// The definition of a new allocation price to create and add to the subscription. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for + /// the replacement price. + /// + [System::Obsolete("deprecated")] + public IReadOnlyList? Discounts + { + get + { + return JsonModel.GetNullableClass>(this.RawData, "discounts"); + } + init { JsonModel.Set(this._rawData, "discounts", value); } + } + + /// + /// The external price id of the price to add to the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// The new quantity of the price, if the price is a fixed price. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount + /// for the replacement price. + /// + [System::Obsolete("deprecated")] + public string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount + /// for the replacement price. + /// + [System::Obsolete("deprecated")] + public string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// New subscription price request body params. + /// + public ReplacePricePrice? Price + { + get { return JsonModel.GetNullableClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// The id of the price to add to the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.ReplacesPriceID; + this.AllocationPrice?.Validate(); + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.MaximumAmount; + _ = this.MinimumAmount; + this.Price?.Validate(); + _ = this.PriceID; + } + + public ReplacePrice() { } + + public ReplacePrice(ReplacePrice replacePrice) + : base(replacePrice) { } + + public ReplacePrice(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePrice FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePrice(string replacesPriceID) + : this() + { + this.ReplacesPriceID = replacesPriceID; + } +} + +class ReplacePriceFromRaw : IFromRawJson +{ + /// + public ReplacePrice FromRawUnchecked(IReadOnlyDictionary rawData) => + ReplacePrice.FromRawUnchecked(rawData); +} + +/// +/// New subscription price request body params. +/// +[JsonConverter(typeof(ReplacePricePriceConverter))] +public record class ReplacePricePrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ItemID, + newSubscriptionTiered: (x) => x.ItemID, + newSubscriptionBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newSubscriptionPackage: (x) => x.ItemID, + newSubscriptionMatrix: (x) => x.ItemID, + newSubscriptionThresholdTotalAmount: (x) => x.ItemID, + newSubscriptionTieredPackage: (x) => x.ItemID, + newSubscriptionTieredWithMinimum: (x) => x.ItemID, + newSubscriptionGroupedTiered: (x) => x.ItemID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ItemID, + newSubscriptionPackageWithAllocation: (x) => x.ItemID, + newSubscriptionUnitWithPercent: (x) => x.ItemID, + newSubscriptionMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newSubscriptionUnitWithProration: (x) => x.ItemID, + newSubscriptionGroupedAllocation: (x) => x.ItemID, + newSubscriptionBulkWithProration: (x) => x.ItemID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ItemID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newSubscriptionMatrixWithDisplayName: (x) => x.ItemID, + newSubscriptionGroupedTieredPackage: (x) => x.ItemID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ItemID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ItemID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ItemID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newSubscriptionMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Name, + newSubscriptionTiered: (x) => x.Name, + newSubscriptionBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newSubscriptionPackage: (x) => x.Name, + newSubscriptionMatrix: (x) => x.Name, + newSubscriptionThresholdTotalAmount: (x) => x.Name, + newSubscriptionTieredPackage: (x) => x.Name, + newSubscriptionTieredWithMinimum: (x) => x.Name, + newSubscriptionGroupedTiered: (x) => x.Name, + newSubscriptionTieredPackageWithMinimum: (x) => x.Name, + newSubscriptionPackageWithAllocation: (x) => x.Name, + newSubscriptionUnitWithPercent: (x) => x.Name, + newSubscriptionMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newSubscriptionUnitWithProration: (x) => x.Name, + newSubscriptionGroupedAllocation: (x) => x.Name, + newSubscriptionBulkWithProration: (x) => x.Name, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Name, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newSubscriptionMatrixWithDisplayName: (x) => x.Name, + newSubscriptionGroupedTieredPackage: (x) => x.Name, + newSubscriptionMaxGroupTieredPackage: (x) => x.Name, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Name, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Name, + newSubscriptionCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newSubscriptionMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillableMetricID, + newSubscriptionTiered: (x) => x.BillableMetricID, + newSubscriptionBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newSubscriptionPackage: (x) => x.BillableMetricID, + newSubscriptionMatrix: (x) => x.BillableMetricID, + newSubscriptionThresholdTotalAmount: (x) => x.BillableMetricID, + newSubscriptionTieredPackage: (x) => x.BillableMetricID, + newSubscriptionTieredWithMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedTiered: (x) => x.BillableMetricID, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillableMetricID, + newSubscriptionPackageWithAllocation: (x) => x.BillableMetricID, + newSubscriptionUnitWithPercent: (x) => x.BillableMetricID, + newSubscriptionMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newSubscriptionUnitWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionBulkWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newSubscriptionMatrixWithDisplayName: (x) => x.BillableMetricID, + newSubscriptionGroupedTieredPackage: (x) => x.BillableMetricID, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BilledInAdvance, + newSubscriptionTiered: (x) => x.BilledInAdvance, + newSubscriptionBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newSubscriptionPackage: (x) => x.BilledInAdvance, + newSubscriptionMatrix: (x) => x.BilledInAdvance, + newSubscriptionThresholdTotalAmount: (x) => x.BilledInAdvance, + newSubscriptionTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionTieredWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedTiered: (x) => x.BilledInAdvance, + newSubscriptionTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionPackageWithAllocation: (x) => x.BilledInAdvance, + newSubscriptionUnitWithPercent: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newSubscriptionUnitWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionBulkWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithDisplayName: (x) => x.BilledInAdvance, + newSubscriptionGroupedTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newSubscriptionCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillingCycleConfiguration, + newSubscriptionTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newSubscriptionPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrix: (x) => x.BillingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ConversionRate, + newSubscriptionTiered: (x) => x.ConversionRate, + newSubscriptionBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newSubscriptionPackage: (x) => x.ConversionRate, + newSubscriptionMatrix: (x) => x.ConversionRate, + newSubscriptionThresholdTotalAmount: (x) => x.ConversionRate, + newSubscriptionTieredPackage: (x) => x.ConversionRate, + newSubscriptionTieredWithMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedTiered: (x) => x.ConversionRate, + newSubscriptionTieredPackageWithMinimum: (x) => x.ConversionRate, + newSubscriptionPackageWithAllocation: (x) => x.ConversionRate, + newSubscriptionUnitWithPercent: (x) => x.ConversionRate, + newSubscriptionMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newSubscriptionUnitWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionBulkWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newSubscriptionMatrixWithDisplayName: (x) => x.ConversionRate, + newSubscriptionGroupedTieredPackage: (x) => x.ConversionRate, + newSubscriptionMaxGroupTieredPackage: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newSubscriptionCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Currency, + newSubscriptionTiered: (x) => x.Currency, + newSubscriptionBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newSubscriptionPackage: (x) => x.Currency, + newSubscriptionMatrix: (x) => x.Currency, + newSubscriptionThresholdTotalAmount: (x) => x.Currency, + newSubscriptionTieredPackage: (x) => x.Currency, + newSubscriptionTieredWithMinimum: (x) => x.Currency, + newSubscriptionGroupedTiered: (x) => x.Currency, + newSubscriptionTieredPackageWithMinimum: (x) => x.Currency, + newSubscriptionPackageWithAllocation: (x) => x.Currency, + newSubscriptionUnitWithPercent: (x) => x.Currency, + newSubscriptionMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newSubscriptionUnitWithProration: (x) => x.Currency, + newSubscriptionGroupedAllocation: (x) => x.Currency, + newSubscriptionBulkWithProration: (x) => x.Currency, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Currency, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newSubscriptionMatrixWithDisplayName: (x) => x.Currency, + newSubscriptionGroupedTieredPackage: (x) => x.Currency, + newSubscriptionMaxGroupTieredPackage: (x) => x.Currency, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Currency, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Currency, + newSubscriptionCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newSubscriptionMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrix: (x) => x.DimensionalPriceConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ExternalPriceID, + newSubscriptionTiered: (x) => x.ExternalPriceID, + newSubscriptionBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newSubscriptionPackage: (x) => x.ExternalPriceID, + newSubscriptionMatrix: (x) => x.ExternalPriceID, + newSubscriptionThresholdTotalAmount: (x) => x.ExternalPriceID, + newSubscriptionTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionTieredWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedTiered: (x) => x.ExternalPriceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionPackageWithAllocation: (x) => x.ExternalPriceID, + newSubscriptionUnitWithPercent: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newSubscriptionUnitWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionBulkWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ExternalPriceID, + newSubscriptionGroupedTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newSubscriptionUnit: (x) => x.FixedPriceQuantity, + newSubscriptionTiered: (x) => x.FixedPriceQuantity, + newSubscriptionBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newSubscriptionPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMatrix: (x) => x.FixedPriceQuantity, + newSubscriptionThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionTieredWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTiered: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionPackageWithAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithPercent: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionBulkWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newSubscriptionCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoiceGroupingKey, + newSubscriptionTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newSubscriptionPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrix: (x) => x.InvoiceGroupingKey, + newSubscriptionThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithPercent: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionBulkWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrix: (x) => x.InvoicingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.InvoicingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ReferenceID, + newSubscriptionTiered: (x) => x.ReferenceID, + newSubscriptionBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newSubscriptionPackage: (x) => x.ReferenceID, + newSubscriptionMatrix: (x) => x.ReferenceID, + newSubscriptionThresholdTotalAmount: (x) => x.ReferenceID, + newSubscriptionTieredPackage: (x) => x.ReferenceID, + newSubscriptionTieredWithMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedTiered: (x) => x.ReferenceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ReferenceID, + newSubscriptionPackageWithAllocation: (x) => x.ReferenceID, + newSubscriptionUnitWithPercent: (x) => x.ReferenceID, + newSubscriptionMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newSubscriptionUnitWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionBulkWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ReferenceID, + newSubscriptionGroupedTieredPackage: (x) => x.ReferenceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public ReplacePricePrice(NewSubscriptionUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(ReplacePricePriceBulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionThresholdTotalAmountPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionTieredWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionTieredPackageWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionPackageWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(NewSubscriptionUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionMatrixWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + ReplacePricePriceTieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionUnitWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionGroupedAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionBulkWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionGroupedWithProratedMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionGroupedWithMeteredMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + ReplacePricePriceGroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionMatrixWithDisplayNamePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionGroupedTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionMaxGroupTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionCumulativeGroupedBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + ReplacePricePriceCumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice( + NewSubscriptionMinimumCompositePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(ReplacePricePricePercent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(ReplacePricePriceEventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnit(out var value)) { + /// // `value` is of type `NewSubscriptionUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnit([NotNullWhen(true)] out NewSubscriptionUnitPrice? value) + { + value = this.Value as NewSubscriptionUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTiered(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTiered( + [NotNullWhen(true)] out NewSubscriptionTieredPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulk(out var value)) { + /// // `value` is of type `NewSubscriptionBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulk([NotNullWhen(true)] out NewSubscriptionBulkPrice? value) + { + value = this.Value as NewSubscriptionBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `ReplacePricePriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] out ReplacePricePriceBulkWithFilters? value + ) + { + value = this.Value as ReplacePricePriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackage(out var value)) { + /// // `value` is of type `NewSubscriptionPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackage( + [NotNullWhen(true)] out NewSubscriptionPackagePrice? value + ) + { + value = this.Value as NewSubscriptionPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrix(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrix( + [NotNullWhen(true)] out NewSubscriptionMatrixPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewSubscriptionThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionThresholdTotalAmount( + [NotNullWhen(true)] out NewSubscriptionThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewSubscriptionThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackage( + [NotNullWhen(true)] out NewSubscriptionTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTiered(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTiered( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackageWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackageWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackageWithAllocation( + [NotNullWhen(true)] out NewSubscriptionPackageWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithPercent(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithPercent( + [NotNullWhen(true)] out NewSubscriptionUnitWithPercentPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithAllocation( + [NotNullWhen(true)] out NewSubscriptionMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `ReplacePricePriceTieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] out ReplacePricePriceTieredWithProration? value + ) + { + value = this.Value as ReplacePricePriceTieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithProration( + [NotNullWhen(true)] out NewSubscriptionUnitWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedAllocation( + [NotNullWhen(true)] out NewSubscriptionGroupedAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulkWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulkWithProration( + [NotNullWhen(true)] out NewSubscriptionBulkWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `ReplacePricePriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out ReplacePricePriceGroupedWithMinMaxThresholds? value + ) + { + value = this.Value as ReplacePricePriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithDisplayName( + [NotNullWhen(true)] out NewSubscriptionMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTieredPackage( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMaxGroupTieredPackage( + [NotNullWhen(true)] out NewSubscriptionMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewSubscriptionCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionCumulativeGroupedBulk( + [NotNullWhen(true)] out NewSubscriptionCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewSubscriptionCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `ReplacePricePriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out ReplacePricePriceCumulativeGroupedAllocation? value + ) + { + value = this.Value as ReplacePricePriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMinimumComposite(out var value)) { + /// // `value` is of type `NewSubscriptionMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMinimumComposite( + [NotNullWhen(true)] out NewSubscriptionMinimumCompositePrice? value + ) + { + value = this.Value as NewSubscriptionMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `ReplacePricePricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out ReplacePricePricePercent? value) + { + value = this.Value as ReplacePricePricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `ReplacePricePriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput([NotNullWhen(true)] out ReplacePricePriceEventOutput? value) + { + value = this.Value as ReplacePricePriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (ReplacePricePriceBulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (ReplacePricePriceTieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (ReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (ReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (ReplacePricePricePercent value) => {...}, + /// (ReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newSubscriptionUnit, + System::Action newSubscriptionTiered, + System::Action newSubscriptionBulk, + System::Action bulkWithFilters, + System::Action newSubscriptionPackage, + System::Action newSubscriptionMatrix, + System::Action newSubscriptionThresholdTotalAmount, + System::Action newSubscriptionTieredPackage, + System::Action newSubscriptionTieredWithMinimum, + System::Action newSubscriptionGroupedTiered, + System::Action newSubscriptionTieredPackageWithMinimum, + System::Action newSubscriptionPackageWithAllocation, + System::Action newSubscriptionUnitWithPercent, + System::Action newSubscriptionMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newSubscriptionUnitWithProration, + System::Action newSubscriptionGroupedAllocation, + System::Action newSubscriptionBulkWithProration, + System::Action newSubscriptionGroupedWithProratedMinimum, + System::Action newSubscriptionGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newSubscriptionMatrixWithDisplayName, + System::Action newSubscriptionGroupedTieredPackage, + System::Action newSubscriptionMaxGroupTieredPackage, + System::Action newSubscriptionScalableMatrixWithUnitPricing, + System::Action newSubscriptionScalableMatrixWithTieredPricing, + System::Action newSubscriptionCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newSubscriptionMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewSubscriptionUnitPrice value: + newSubscriptionUnit(value); + break; + case NewSubscriptionTieredPrice value: + newSubscriptionTiered(value); + break; + case NewSubscriptionBulkPrice value: + newSubscriptionBulk(value); + break; + case ReplacePricePriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewSubscriptionPackagePrice value: + newSubscriptionPackage(value); + break; + case NewSubscriptionMatrixPrice value: + newSubscriptionMatrix(value); + break; + case NewSubscriptionThresholdTotalAmountPrice value: + newSubscriptionThresholdTotalAmount(value); + break; + case NewSubscriptionTieredPackagePrice value: + newSubscriptionTieredPackage(value); + break; + case NewSubscriptionTieredWithMinimumPrice value: + newSubscriptionTieredWithMinimum(value); + break; + case NewSubscriptionGroupedTieredPrice value: + newSubscriptionGroupedTiered(value); + break; + case NewSubscriptionTieredPackageWithMinimumPrice value: + newSubscriptionTieredPackageWithMinimum(value); + break; + case NewSubscriptionPackageWithAllocationPrice value: + newSubscriptionPackageWithAllocation(value); + break; + case NewSubscriptionUnitWithPercentPrice value: + newSubscriptionUnitWithPercent(value); + break; + case NewSubscriptionMatrixWithAllocationPrice value: + newSubscriptionMatrixWithAllocation(value); + break; + case ReplacePricePriceTieredWithProration value: + tieredWithProration(value); + break; + case NewSubscriptionUnitWithProrationPrice value: + newSubscriptionUnitWithProration(value); + break; + case NewSubscriptionGroupedAllocationPrice value: + newSubscriptionGroupedAllocation(value); + break; + case NewSubscriptionBulkWithProrationPrice value: + newSubscriptionBulkWithProration(value); + break; + case NewSubscriptionGroupedWithProratedMinimumPrice value: + newSubscriptionGroupedWithProratedMinimum(value); + break; + case NewSubscriptionGroupedWithMeteredMinimumPrice value: + newSubscriptionGroupedWithMeteredMinimum(value); + break; + case ReplacePricePriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewSubscriptionMatrixWithDisplayNamePrice value: + newSubscriptionMatrixWithDisplayName(value); + break; + case NewSubscriptionGroupedTieredPackagePrice value: + newSubscriptionGroupedTieredPackage(value); + break; + case NewSubscriptionMaxGroupTieredPackagePrice value: + newSubscriptionMaxGroupTieredPackage(value); + break; + case NewSubscriptionScalableMatrixWithUnitPricingPrice value: + newSubscriptionScalableMatrixWithUnitPricing(value); + break; + case NewSubscriptionScalableMatrixWithTieredPricingPrice value: + newSubscriptionScalableMatrixWithTieredPricing(value); + break; + case NewSubscriptionCumulativeGroupedBulkPrice value: + newSubscriptionCumulativeGroupedBulk(value); + break; + case ReplacePricePriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewSubscriptionMinimumCompositePrice value: + newSubscriptionMinimumComposite(value); + break; + case ReplacePricePricePercent value: + percent(value); + break; + case ReplacePricePriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (ReplacePricePriceBulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (ReplacePricePriceTieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (ReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (ReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (ReplacePricePricePercent value) => {...}, + /// (ReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newSubscriptionUnit, + System::Func newSubscriptionTiered, + System::Func newSubscriptionBulk, + System::Func bulkWithFilters, + System::Func newSubscriptionPackage, + System::Func newSubscriptionMatrix, + System::Func< + NewSubscriptionThresholdTotalAmountPrice, + T + > newSubscriptionThresholdTotalAmount, + System::Func newSubscriptionTieredPackage, + System::Func newSubscriptionTieredWithMinimum, + System::Func newSubscriptionGroupedTiered, + System::Func< + NewSubscriptionTieredPackageWithMinimumPrice, + T + > newSubscriptionTieredPackageWithMinimum, + System::Func< + NewSubscriptionPackageWithAllocationPrice, + T + > newSubscriptionPackageWithAllocation, + System::Func newSubscriptionUnitWithPercent, + System::Func< + NewSubscriptionMatrixWithAllocationPrice, + T + > newSubscriptionMatrixWithAllocation, + System::Func tieredWithProration, + System::Func newSubscriptionUnitWithProration, + System::Func newSubscriptionGroupedAllocation, + System::Func newSubscriptionBulkWithProration, + System::Func< + NewSubscriptionGroupedWithProratedMinimumPrice, + T + > newSubscriptionGroupedWithProratedMinimum, + System::Func< + NewSubscriptionGroupedWithMeteredMinimumPrice, + T + > newSubscriptionGroupedWithMeteredMinimum, + System::Func groupedWithMinMaxThresholds, + System::Func< + NewSubscriptionMatrixWithDisplayNamePrice, + T + > newSubscriptionMatrixWithDisplayName, + System::Func< + NewSubscriptionGroupedTieredPackagePrice, + T + > newSubscriptionGroupedTieredPackage, + System::Func< + NewSubscriptionMaxGroupTieredPackagePrice, + T + > newSubscriptionMaxGroupTieredPackage, + System::Func< + NewSubscriptionScalableMatrixWithUnitPricingPrice, + T + > newSubscriptionScalableMatrixWithUnitPricing, + System::Func< + NewSubscriptionScalableMatrixWithTieredPricingPrice, + T + > newSubscriptionScalableMatrixWithTieredPricing, + System::Func< + NewSubscriptionCumulativeGroupedBulkPrice, + T + > newSubscriptionCumulativeGroupedBulk, + System::Func cumulativeGroupedAllocation, + System::Func newSubscriptionMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewSubscriptionUnitPrice value => newSubscriptionUnit(value), + NewSubscriptionTieredPrice value => newSubscriptionTiered(value), + NewSubscriptionBulkPrice value => newSubscriptionBulk(value), + ReplacePricePriceBulkWithFilters value => bulkWithFilters(value), + NewSubscriptionPackagePrice value => newSubscriptionPackage(value), + NewSubscriptionMatrixPrice value => newSubscriptionMatrix(value), + NewSubscriptionThresholdTotalAmountPrice value => newSubscriptionThresholdTotalAmount( + value + ), + NewSubscriptionTieredPackagePrice value => newSubscriptionTieredPackage(value), + NewSubscriptionTieredWithMinimumPrice value => newSubscriptionTieredWithMinimum(value), + NewSubscriptionGroupedTieredPrice value => newSubscriptionGroupedTiered(value), + NewSubscriptionTieredPackageWithMinimumPrice value => + newSubscriptionTieredPackageWithMinimum(value), + NewSubscriptionPackageWithAllocationPrice value => newSubscriptionPackageWithAllocation( + value + ), + NewSubscriptionUnitWithPercentPrice value => newSubscriptionUnitWithPercent(value), + NewSubscriptionMatrixWithAllocationPrice value => newSubscriptionMatrixWithAllocation( + value + ), + ReplacePricePriceTieredWithProration value => tieredWithProration(value), + NewSubscriptionUnitWithProrationPrice value => newSubscriptionUnitWithProration(value), + NewSubscriptionGroupedAllocationPrice value => newSubscriptionGroupedAllocation(value), + NewSubscriptionBulkWithProrationPrice value => newSubscriptionBulkWithProration(value), + NewSubscriptionGroupedWithProratedMinimumPrice value => + newSubscriptionGroupedWithProratedMinimum(value), + NewSubscriptionGroupedWithMeteredMinimumPrice value => + newSubscriptionGroupedWithMeteredMinimum(value), + ReplacePricePriceGroupedWithMinMaxThresholds value => groupedWithMinMaxThresholds( + value + ), + NewSubscriptionMatrixWithDisplayNamePrice value => newSubscriptionMatrixWithDisplayName( + value + ), + NewSubscriptionGroupedTieredPackagePrice value => newSubscriptionGroupedTieredPackage( + value + ), + NewSubscriptionMaxGroupTieredPackagePrice value => newSubscriptionMaxGroupTieredPackage( + value + ), + NewSubscriptionScalableMatrixWithUnitPricingPrice value => + newSubscriptionScalableMatrixWithUnitPricing(value), + NewSubscriptionScalableMatrixWithTieredPricingPrice value => + newSubscriptionScalableMatrixWithTieredPricing(value), + NewSubscriptionCumulativeGroupedBulkPrice value => newSubscriptionCumulativeGroupedBulk( + value + ), + ReplacePricePriceCumulativeGroupedAllocation value => cumulativeGroupedAllocation( + value + ), + NewSubscriptionMinimumCompositePrice value => newSubscriptionMinimumComposite(value), + ReplacePricePricePercent value => percent(value), + ReplacePricePriceEventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ), + }; + } + + public static implicit operator ReplacePricePrice(NewSubscriptionUnitPrice value) => new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionTieredPrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionBulkPrice value) => new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePriceBulkWithFilters value) => + new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionPackagePrice value) => + new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionMatrixPrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionTieredPackagePrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionGroupedTieredPrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionUnitWithPercentPrice value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePriceTieredWithProration value) => + new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionUnitWithProrationPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionGroupedAllocationPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionBulkWithProrationPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + ReplacePricePriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + NewSubscriptionCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator ReplacePricePrice( + ReplacePricePriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator ReplacePricePrice(NewSubscriptionMinimumCompositePrice value) => + new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePricePercent value) => new(value); + + public static implicit operator ReplacePricePrice(ReplacePricePriceEventOutput value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePrice" + ); + } + this.Switch( + (newSubscriptionUnit) => newSubscriptionUnit.Validate(), + (newSubscriptionTiered) => newSubscriptionTiered.Validate(), + (newSubscriptionBulk) => newSubscriptionBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newSubscriptionPackage) => newSubscriptionPackage.Validate(), + (newSubscriptionMatrix) => newSubscriptionMatrix.Validate(), + (newSubscriptionThresholdTotalAmount) => newSubscriptionThresholdTotalAmount.Validate(), + (newSubscriptionTieredPackage) => newSubscriptionTieredPackage.Validate(), + (newSubscriptionTieredWithMinimum) => newSubscriptionTieredWithMinimum.Validate(), + (newSubscriptionGroupedTiered) => newSubscriptionGroupedTiered.Validate(), + (newSubscriptionTieredPackageWithMinimum) => + newSubscriptionTieredPackageWithMinimum.Validate(), + (newSubscriptionPackageWithAllocation) => + newSubscriptionPackageWithAllocation.Validate(), + (newSubscriptionUnitWithPercent) => newSubscriptionUnitWithPercent.Validate(), + (newSubscriptionMatrixWithAllocation) => newSubscriptionMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newSubscriptionUnitWithProration) => newSubscriptionUnitWithProration.Validate(), + (newSubscriptionGroupedAllocation) => newSubscriptionGroupedAllocation.Validate(), + (newSubscriptionBulkWithProration) => newSubscriptionBulkWithProration.Validate(), + (newSubscriptionGroupedWithProratedMinimum) => + newSubscriptionGroupedWithProratedMinimum.Validate(), + (newSubscriptionGroupedWithMeteredMinimum) => + newSubscriptionGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newSubscriptionMatrixWithDisplayName) => + newSubscriptionMatrixWithDisplayName.Validate(), + (newSubscriptionGroupedTieredPackage) => newSubscriptionGroupedTieredPackage.Validate(), + (newSubscriptionMaxGroupTieredPackage) => + newSubscriptionMaxGroupTieredPackage.Validate(), + (newSubscriptionScalableMatrixWithUnitPricing) => + newSubscriptionScalableMatrixWithUnitPricing.Validate(), + (newSubscriptionScalableMatrixWithTieredPricing) => + newSubscriptionScalableMatrixWithTieredPricing.Validate(), + (newSubscriptionCumulativeGroupedBulk) => + newSubscriptionCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newSubscriptionMinimumComposite) => newSubscriptionMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(ReplacePricePrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceConverter : JsonConverter +{ + public override ReplacePricePrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFilters, + ReplacePricePriceBulkWithFiltersFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public ReplacePricePriceBulkWithFilters( + ReplacePricePriceBulkWithFilters replacePricePriceBulkWithFilters + ) + : base(replacePricePriceBulkWithFilters) { } + + public ReplacePricePriceBulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersFromRaw : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig, + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig replacePricePriceBulkWithFiltersBulkWithFiltersConfig + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfig) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter, + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter replacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier, + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier() { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier replacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base(replacePricePriceBulkWithFiltersBulkWithFiltersConfigTier) { } + + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceBulkWithFiltersCadenceConverter))] +public enum ReplacePricePriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceBulkWithFiltersCadence.Annual, + "semi_annual" => ReplacePricePriceBulkWithFiltersCadence.SemiAnnual, + "monthly" => ReplacePricePriceBulkWithFiltersCadence.Monthly, + "quarterly" => ReplacePricePriceBulkWithFiltersCadence.Quarterly, + "one_time" => ReplacePricePriceBulkWithFiltersCadence.OneTime, + "custom" => ReplacePricePriceBulkWithFiltersCadence.Custom, + _ => (ReplacePricePriceBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceBulkWithFiltersCadence.Annual => "annual", + ReplacePricePriceBulkWithFiltersCadence.SemiAnnual => "semi_annual", + ReplacePricePriceBulkWithFiltersCadence.Monthly => "monthly", + ReplacePricePriceBulkWithFiltersCadence.Quarterly => "quarterly", + ReplacePricePriceBulkWithFiltersCadence.OneTime => "one_time", + ReplacePricePriceBulkWithFiltersCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(ReplacePricePriceBulkWithFiltersConversionRateConfigConverter))] +public record class ReplacePricePriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceBulkWithFiltersConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePriceBulkWithFiltersConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceBulkWithFiltersConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceTieredWithProration, + ReplacePricePriceTieredWithProrationFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProration : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required ReplacePricePriceTieredWithProrationTieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceTieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceTieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public ReplacePricePriceTieredWithProration( + ReplacePricePriceTieredWithProration replacePricePriceTieredWithProration + ) + : base(replacePricePriceTieredWithProration) { } + + public ReplacePricePriceTieredWithProration(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProration(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceTieredWithProrationFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceTieredWithProration.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceTieredWithProrationCadenceConverter))] +public enum ReplacePricePriceTieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceTieredWithProrationCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceTieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceTieredWithProrationCadence.Annual, + "semi_annual" => ReplacePricePriceTieredWithProrationCadence.SemiAnnual, + "monthly" => ReplacePricePriceTieredWithProrationCadence.Monthly, + "quarterly" => ReplacePricePriceTieredWithProrationCadence.Quarterly, + "one_time" => ReplacePricePriceTieredWithProrationCadence.OneTime, + "custom" => ReplacePricePriceTieredWithProrationCadence.Custom, + _ => (ReplacePricePriceTieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceTieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceTieredWithProrationCadence.Annual => "annual", + ReplacePricePriceTieredWithProrationCadence.SemiAnnual => "semi_annual", + ReplacePricePriceTieredWithProrationCadence.Monthly => "monthly", + ReplacePricePriceTieredWithProrationCadence.Quarterly => "quarterly", + ReplacePricePriceTieredWithProrationCadence.OneTime => "one_time", + ReplacePricePriceTieredWithProrationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceTieredWithProrationTieredWithProrationConfig, + ReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProrationTieredWithProrationConfig : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig() { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + ReplacePricePriceTieredWithProrationTieredWithProrationConfig replacePricePriceTieredWithProrationTieredWithProrationConfig + ) + : base(replacePricePriceTieredWithProrationTieredWithProrationConfig) { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class ReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceTieredWithProrationTieredWithProrationConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier, + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier() { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier replacePricePriceTieredWithProrationTieredWithProrationConfigTier + ) + : base(replacePricePriceTieredWithProrationTieredWithProrationConfigTier) { } + + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ReplacePricePriceTieredWithProrationTieredWithProrationConfigTier.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReplacePricePriceTieredWithProrationConversionRateConfigConverter))] +public record class ReplacePricePriceTieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceTieredWithProrationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePriceTieredWithProrationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceTieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceTieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceTieredWithProrationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceTieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceGroupedWithMinMaxThresholds, + ReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class ReplacePricePriceGroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public ReplacePricePriceGroupedWithMinMaxThresholds( + ReplacePricePriceGroupedWithMinMaxThresholds replacePricePriceGroupedWithMinMaxThresholds + ) + : base(replacePricePriceGroupedWithMinMaxThresholds) { } + + public ReplacePricePriceGroupedWithMinMaxThresholds( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceGroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceGroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter))] +public enum ReplacePricePriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom, + _ => (ReplacePricePriceGroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual => "annual", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual => "semi_annual", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly => "quarterly", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + ReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() { } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig replacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base(replacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig) { } + + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter))] +public record class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceCumulativeGroupedAllocation, + ReplacePricePriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class ReplacePricePriceCumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public ReplacePricePriceCumulativeGroupedAllocation( + ReplacePricePriceCumulativeGroupedAllocation replacePricePriceCumulativeGroupedAllocation + ) + : base(replacePricePriceCumulativeGroupedAllocation) { } + + public ReplacePricePriceCumulativeGroupedAllocation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceCumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceCumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceCumulativeGroupedAllocationCadenceConverter))] +public enum ReplacePricePriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime, + "custom" => ReplacePricePriceCumulativeGroupedAllocationCadence.Custom, + _ => (ReplacePricePriceCumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceCumulativeGroupedAllocationCadence.Annual => "annual", + ReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual => "semi_annual", + ReplacePricePriceCumulativeGroupedAllocationCadence.Monthly => "monthly", + ReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly => "quarterly", + ReplacePricePriceCumulativeGroupedAllocationCadence.OneTime => "one_time", + ReplacePricePriceCumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() { } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig replacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base(replacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig) { } + + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + ReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter))] +public record class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ReplacePricePricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required ReplacePricePricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public ReplacePricePricePercent(ReplacePricePricePercent replacePricePricePercent) + : base(replacePricePricePercent) { } + + public ReplacePricePricePercent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePricePercent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePricePercentFromRaw : IFromRawJson +{ + /// + public ReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePricePercentCadenceConverter))] +public enum ReplacePricePricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePricePercentCadenceConverter + : JsonConverter +{ + public override ReplacePricePricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePricePercentCadence.Annual, + "semi_annual" => ReplacePricePricePercentCadence.SemiAnnual, + "monthly" => ReplacePricePricePercentCadence.Monthly, + "quarterly" => ReplacePricePricePercentCadence.Quarterly, + "one_time" => ReplacePricePricePercentCadence.OneTime, + "custom" => ReplacePricePricePercentCadence.Custom, + _ => (ReplacePricePricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePricePercentCadence.Annual => "annual", + ReplacePricePricePercentCadence.SemiAnnual => "semi_annual", + ReplacePricePricePercentCadence.Monthly => "monthly", + ReplacePricePricePercentCadence.Quarterly => "quarterly", + ReplacePricePricePercentCadence.OneTime => "one_time", + ReplacePricePricePercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePricePercentPercentConfig, + ReplacePricePricePercentPercentConfigFromRaw + >) +)] +public sealed record class ReplacePricePricePercentPercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public ReplacePricePricePercentPercentConfig() { } + + public ReplacePricePricePercentPercentConfig( + ReplacePricePricePercentPercentConfig replacePricePricePercentPercentConfig + ) + : base(replacePricePricePercentPercentConfig) { } + + public ReplacePricePricePercentPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePricePercentPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class ReplacePricePricePercentPercentConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePricePercentPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReplacePricePricePercentConversionRateConfigConverter))] +public record class ReplacePricePricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePricePercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePricePercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePricePercentConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePricePercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class ReplacePricePriceEventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required ReplacePricePriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public ReplacePricePriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public ReplacePricePriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public ReplacePricePriceEventOutput(ReplacePricePriceEventOutput replacePricePriceEventOutput) + : base(replacePricePriceEventOutput) { } + + public ReplacePricePriceEventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceEventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ReplacePricePriceEventOutputFromRaw : IFromRawJson +{ + /// + public ReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(ReplacePricePriceEventOutputCadenceConverter))] +public enum ReplacePricePriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class ReplacePricePriceEventOutputCadenceConverter + : JsonConverter +{ + public override ReplacePricePriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => ReplacePricePriceEventOutputCadence.Annual, + "semi_annual" => ReplacePricePriceEventOutputCadence.SemiAnnual, + "monthly" => ReplacePricePriceEventOutputCadence.Monthly, + "quarterly" => ReplacePricePriceEventOutputCadence.Quarterly, + "one_time" => ReplacePricePriceEventOutputCadence.OneTime, + "custom" => ReplacePricePriceEventOutputCadence.Custom, + _ => (ReplacePricePriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ReplacePricePriceEventOutputCadence.Annual => "annual", + ReplacePricePriceEventOutputCadence.SemiAnnual => "semi_annual", + ReplacePricePriceEventOutputCadence.Monthly => "monthly", + ReplacePricePriceEventOutputCadence.Quarterly => "quarterly", + ReplacePricePriceEventOutputCadence.OneTime => "one_time", + ReplacePricePriceEventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + ReplacePricePriceEventOutputEventOutputConfig, + ReplacePricePriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class ReplacePricePriceEventOutputEventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public ReplacePricePriceEventOutputEventOutputConfig() { } + + public ReplacePricePriceEventOutputEventOutputConfig( + ReplacePricePriceEventOutputEventOutputConfig replacePricePriceEventOutputEventOutputConfig + ) + : base(replacePricePriceEventOutputEventOutputConfig) { } + + public ReplacePricePriceEventOutputEventOutputConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ReplacePricePriceEventOutputEventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static ReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ReplacePricePriceEventOutputEventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class ReplacePricePriceEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public ReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ReplacePricePriceEventOutputEventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(ReplacePricePriceEventOutputConversionRateConfigConverter))] +public record class ReplacePricePriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public ReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ReplacePricePriceEventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator ReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator ReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of ReplacePricePriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(ReplacePricePriceEventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class ReplacePricePriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override ReplacePricePriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new ReplacePricePriceEventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + ReplacePricePriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustment.cs deleted file mode 100644 index ca0f4628..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustment.cs +++ /dev/null @@ -1,108 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddAdjustmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the subscription. - /// - public required AddAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the adjustment interval. This is the date that the adjustment - /// will stop affecting prices on the subscription. - /// - public System::DateTime? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this adjustment to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The start date of the adjustment interval. This is the date that the adjustment - /// will start affecting prices on the subscription. If null, the adjustment will - /// start when the phase or subscription starts. - /// - public System::DateTime? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.EndDate; - _ = this.PlanPhaseOrder; - _ = this.StartDate; - } - - public AddAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustmentProperties/Adjustment.cs deleted file mode 100644 index ad97f7cb..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index fcfcbf1a..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPrice.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPrice.cs deleted file mode 100644 index f8297abd..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPrice.cs +++ /dev/null @@ -1,215 +0,0 @@ -using AddPriceProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddPriceProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddPrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new allocation price to create and add to the subscription. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for this price. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the price interval. This is the date that the price will stop - /// billing on the subscription. If null, billing will end when the phase or subscription ends. - /// - public System::DateTime? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external price id of the price to add to the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount - /// for this price. - /// - public string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount - /// for this price. - /// - public string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this price to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The definition of a new price to create and add to the subscription. - /// - public AddPriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the price to add to the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The start date of the price interval. This is the date that the price will - /// start billing on the subscription. If null, billing will start when the phase - /// or subscription starts. - /// - public System::DateTime? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.AllocationPrice?.Validate(); - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - _ = this.EndDate; - _ = this.ExternalPriceID; - _ = this.MaximumAmount; - _ = this.MinimumAmount; - _ = this.PlanPhaseOrder; - this.Price?.Validate(); - _ = this.PriceID; - _ = this.StartDate; - } - - public AddPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPriceProperties/Price.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPriceProperties/Price.cs deleted file mode 100644 index d21a34a5..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPriceProperties/Price.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Orb = Orb; -using PriceVariants = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddPriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddPriceProperties; - -/// -/// The definition of a new price to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewSubscriptionUnitPrice Create( - Subscriptions::NewSubscriptionUnitPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackagePrice Create( - Subscriptions::NewSubscriptionPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixPrice Create( - Subscriptions::NewSubscriptionMatrixPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPrice Create( - Subscriptions::NewSubscriptionTieredPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredBPSPrice Create( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBPSPrice Create( - Subscriptions::NewSubscriptionBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkBPSPrice Create( - Subscriptions::NewSubscriptionBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkPrice Create( - Subscriptions::NewSubscriptionBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionThresholdTotalAmountPrice Create( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackagePrice Create( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithPercentPrice Create( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackageWithAllocationPrice Create( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTierWithProrationPrice Create( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithProrationPrice Create( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedAllocationPrice Create( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithProratedMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkWithProrationPrice Create( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithUnitPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithTieredPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionCumulativeGroupedBulkPrice Create( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMaxGroupTieredPackagePrice Create( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithMeteredMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithDisplayNamePrice Create( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPackagePrice Create( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithAllocationPrice Create( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackageWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPrice Create( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPriceProperties/PriceVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPriceProperties/PriceVariants/All.cs deleted file mode 100644 index 5012069c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/AddPriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,737 +0,0 @@ -using AddPriceProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.AddPriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionUnitPrice(Subscriptions::NewSubscriptionUnitPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionUnitPrice From(Subscriptions::NewSubscriptionUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackagePrice, - Subscriptions::NewSubscriptionPackagePrice - >) -)] -public sealed record class NewSubscriptionPackagePrice( - Subscriptions::NewSubscriptionPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionPackagePrice From(Subscriptions::NewSubscriptionPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixPrice, - Subscriptions::NewSubscriptionMatrixPrice - >) -)] -public sealed record class NewSubscriptionMatrixPrice( - Subscriptions::NewSubscriptionMatrixPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionMatrixPrice From(Subscriptions::NewSubscriptionMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPrice, - Subscriptions::NewSubscriptionTieredPrice - >) -)] -public sealed record class NewSubscriptionTieredPrice( - Subscriptions::NewSubscriptionTieredPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredPrice From(Subscriptions::NewSubscriptionTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredBPSPrice, - Subscriptions::NewSubscriptionTieredBPSPrice - >) -)] -public sealed record class NewSubscriptionTieredBPSPrice( - Subscriptions::NewSubscriptionTieredBPSPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredBPSPrice From( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBPSPrice(Subscriptions::NewSubscriptionBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBPSPrice From(Subscriptions::NewSubscriptionBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkBPSPrice, - Subscriptions::NewSubscriptionBulkBPSPrice - >) -)] -public sealed record class NewSubscriptionBulkBPSPrice( - Subscriptions::NewSubscriptionBulkBPSPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkBPSPrice From(Subscriptions::NewSubscriptionBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBulkPrice(Subscriptions::NewSubscriptionBulkPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkPrice From(Subscriptions::NewSubscriptionBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - >) -)] -public sealed record class NewSubscriptionThresholdTotalAmountPrice( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - > -{ - public static NewSubscriptionThresholdTotalAmountPrice From( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionTieredPackagePrice( - Subscriptions::NewSubscriptionTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - > -{ - public static NewSubscriptionTieredPackagePrice From( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredWithMinimumPrice( - Subscriptions::NewSubscriptionTieredWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - > -{ - public static NewSubscriptionTieredWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - >) -)] -public sealed record class NewSubscriptionUnitWithPercentPrice( - Subscriptions::NewSubscriptionUnitWithPercentPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - > -{ - public static NewSubscriptionUnitWithPercentPrice From( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionPackageWithAllocationPrice( - Subscriptions::NewSubscriptionPackageWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - > -{ - public static NewSubscriptionPackageWithAllocationPrice From( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - >) -)] -public sealed record class NewSubscriptionTierWithProrationPrice( - Subscriptions::NewSubscriptionTierWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - > -{ - public static NewSubscriptionTierWithProrationPrice From( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - >) -)] -public sealed record class NewSubscriptionUnitWithProrationPrice( - Subscriptions::NewSubscriptionUnitWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - > -{ - public static NewSubscriptionUnitWithProrationPrice From( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - >) -)] -public sealed record class NewSubscriptionGroupedAllocationPrice( - Subscriptions::NewSubscriptionGroupedAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - > -{ - public static NewSubscriptionGroupedAllocationPrice From( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - > -{ - public static NewSubscriptionGroupedWithProratedMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - >) -)] -public sealed record class NewSubscriptionBulkWithProrationPrice( - Subscriptions::NewSubscriptionBulkWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - > -{ - public static NewSubscriptionBulkWithProrationPrice From( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithUnitPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithTieredPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewSubscriptionCumulativeGroupedBulkPrice( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - > -{ - public static NewSubscriptionCumulativeGroupedBulkPrice From( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionMaxGroupTieredPackagePrice( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - > -{ - public static NewSubscriptionMaxGroupTieredPackagePrice From( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - > -{ - public static NewSubscriptionGroupedWithMeteredMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewSubscriptionMatrixWithDisplayNamePrice( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - > -{ - public static NewSubscriptionMatrixWithDisplayNamePrice From( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPackagePrice( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - > -{ - public static NewSubscriptionGroupedTieredPackagePrice From( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionMatrixWithAllocationPrice( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - > -{ - public static NewSubscriptionMatrixWithAllocationPrice From( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredPackageWithMinimumPrice( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - > -{ - public static NewSubscriptionTieredPackageWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPrice( - Subscriptions::NewSubscriptionGroupedTieredPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - > -{ - public static NewSubscriptionGroupedTieredPrice From( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ExternalMarketplace.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ExternalMarketplace.cs deleted file mode 100644 index 8e392435..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ExternalMarketplace.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ExternalMarketplace(string value) - : Orb::IEnum -{ - public static readonly ExternalMarketplace Google = new("google"); - - public static readonly ExternalMarketplace Aws = new("aws"); - - public static readonly ExternalMarketplace Azure = new("azure"); - - readonly string _value = value; - - public enum Value - { - Google, - Aws, - Azure, - } - - public Value Known() => - _value switch - { - "google" => Value.Google, - "aws" => Value.Aws, - "azure" => Value.Azure, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ExternalMarketplace FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/RemoveAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/RemoveAdjustment.cs deleted file mode 100644 index 440e4adf..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/RemoveAdjustment.cs +++ /dev/null @@ -1,53 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemoveAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the adjustment to remove on the subscription. - /// - public required string AdjustmentID - { - get - { - if (!this.Properties.TryGetValue("adjustment_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_id"); - } - set { this.Properties["adjustment_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AdjustmentID; - } - - public RemoveAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemoveAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemoveAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/RemovePrice.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/RemovePrice.cs deleted file mode 100644 index c3d350ae..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/RemovePrice.cs +++ /dev/null @@ -1,67 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemovePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The external price id of the price to remove on the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the price to remove on the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ExternalPriceID; - _ = this.PriceID; - } - - public RemovePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemovePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemovePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustment.cs deleted file mode 100644 index eb73a5ae..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustment.cs +++ /dev/null @@ -1,85 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplaceAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the subscription. - /// - public required ReplaceAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the adjustment on the plan to replace in the subscription. - /// - public required string ReplacesAdjustmentID - { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_adjustment_id"); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.ReplacesAdjustmentID; - } - - public ReplaceAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplaceAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplaceAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs deleted file mode 100644 index 4fa9bdb7..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplaceAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index f24e2dda..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePrice.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePrice.cs deleted file mode 100644 index cad62c49..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePrice.cs +++ /dev/null @@ -1,206 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplacePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price on the plan to replace in the subscription. - /// - public required string ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_price_id"); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The definition of a new allocation price to create and add to the subscription. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for the - /// replacement price. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external price id of the price to add to the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The new quantity of the price, if the price is a fixed price. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount - /// for the replacement price. - /// - public string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount - /// for the replacement price. - /// - public string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The definition of a new price to create and add to the subscription. - /// - public ReplacePriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the price to add to the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ReplacesPriceID; - this.AllocationPrice?.Validate(); - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.MaximumAmount; - _ = this.MinimumAmount; - this.Price?.Validate(); - _ = this.PriceID; - } - - public ReplacePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplacePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplacePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePriceProperties/Price.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePriceProperties/Price.cs deleted file mode 100644 index 11ce3aec..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePriceProperties/Price.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Orb = Orb; -using PriceVariants = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplacePriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplacePriceProperties; - -/// -/// The definition of a new price to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewSubscriptionUnitPrice Create( - Subscriptions::NewSubscriptionUnitPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackagePrice Create( - Subscriptions::NewSubscriptionPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixPrice Create( - Subscriptions::NewSubscriptionMatrixPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPrice Create( - Subscriptions::NewSubscriptionTieredPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredBPSPrice Create( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBPSPrice Create( - Subscriptions::NewSubscriptionBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkBPSPrice Create( - Subscriptions::NewSubscriptionBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkPrice Create( - Subscriptions::NewSubscriptionBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionThresholdTotalAmountPrice Create( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackagePrice Create( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithPercentPrice Create( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackageWithAllocationPrice Create( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTierWithProrationPrice Create( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithProrationPrice Create( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedAllocationPrice Create( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithProratedMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkWithProrationPrice Create( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithUnitPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithTieredPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionCumulativeGroupedBulkPrice Create( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMaxGroupTieredPackagePrice Create( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithMeteredMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithDisplayNamePrice Create( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPackagePrice Create( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithAllocationPrice Create( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackageWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPrice Create( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePriceProperties/PriceVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePriceProperties/PriceVariants/All.cs deleted file mode 100644 index 68eb3614..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionCreateParamsProperties/ReplacePriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,737 +0,0 @@ -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionCreateParamsProperties.ReplacePriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionUnitPrice(Subscriptions::NewSubscriptionUnitPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionUnitPrice From(Subscriptions::NewSubscriptionUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackagePrice, - Subscriptions::NewSubscriptionPackagePrice - >) -)] -public sealed record class NewSubscriptionPackagePrice( - Subscriptions::NewSubscriptionPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionPackagePrice From(Subscriptions::NewSubscriptionPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixPrice, - Subscriptions::NewSubscriptionMatrixPrice - >) -)] -public sealed record class NewSubscriptionMatrixPrice( - Subscriptions::NewSubscriptionMatrixPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionMatrixPrice From(Subscriptions::NewSubscriptionMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPrice, - Subscriptions::NewSubscriptionTieredPrice - >) -)] -public sealed record class NewSubscriptionTieredPrice( - Subscriptions::NewSubscriptionTieredPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredPrice From(Subscriptions::NewSubscriptionTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredBPSPrice, - Subscriptions::NewSubscriptionTieredBPSPrice - >) -)] -public sealed record class NewSubscriptionTieredBPSPrice( - Subscriptions::NewSubscriptionTieredBPSPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredBPSPrice From( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBPSPrice(Subscriptions::NewSubscriptionBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBPSPrice From(Subscriptions::NewSubscriptionBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkBPSPrice, - Subscriptions::NewSubscriptionBulkBPSPrice - >) -)] -public sealed record class NewSubscriptionBulkBPSPrice( - Subscriptions::NewSubscriptionBulkBPSPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkBPSPrice From(Subscriptions::NewSubscriptionBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBulkPrice(Subscriptions::NewSubscriptionBulkPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkPrice From(Subscriptions::NewSubscriptionBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - >) -)] -public sealed record class NewSubscriptionThresholdTotalAmountPrice( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - > -{ - public static NewSubscriptionThresholdTotalAmountPrice From( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionTieredPackagePrice( - Subscriptions::NewSubscriptionTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - > -{ - public static NewSubscriptionTieredPackagePrice From( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredWithMinimumPrice( - Subscriptions::NewSubscriptionTieredWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - > -{ - public static NewSubscriptionTieredWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - >) -)] -public sealed record class NewSubscriptionUnitWithPercentPrice( - Subscriptions::NewSubscriptionUnitWithPercentPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - > -{ - public static NewSubscriptionUnitWithPercentPrice From( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionPackageWithAllocationPrice( - Subscriptions::NewSubscriptionPackageWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - > -{ - public static NewSubscriptionPackageWithAllocationPrice From( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - >) -)] -public sealed record class NewSubscriptionTierWithProrationPrice( - Subscriptions::NewSubscriptionTierWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - > -{ - public static NewSubscriptionTierWithProrationPrice From( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - >) -)] -public sealed record class NewSubscriptionUnitWithProrationPrice( - Subscriptions::NewSubscriptionUnitWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - > -{ - public static NewSubscriptionUnitWithProrationPrice From( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - >) -)] -public sealed record class NewSubscriptionGroupedAllocationPrice( - Subscriptions::NewSubscriptionGroupedAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - > -{ - public static NewSubscriptionGroupedAllocationPrice From( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - > -{ - public static NewSubscriptionGroupedWithProratedMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - >) -)] -public sealed record class NewSubscriptionBulkWithProrationPrice( - Subscriptions::NewSubscriptionBulkWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - > -{ - public static NewSubscriptionBulkWithProrationPrice From( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithUnitPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithTieredPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewSubscriptionCumulativeGroupedBulkPrice( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - > -{ - public static NewSubscriptionCumulativeGroupedBulkPrice From( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionMaxGroupTieredPackagePrice( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - > -{ - public static NewSubscriptionMaxGroupTieredPackagePrice From( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - > -{ - public static NewSubscriptionGroupedWithMeteredMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewSubscriptionMatrixWithDisplayNamePrice( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - > -{ - public static NewSubscriptionMatrixWithDisplayNamePrice From( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPackagePrice( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - > -{ - public static NewSubscriptionGroupedTieredPackagePrice From( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionMatrixWithAllocationPrice( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - > -{ - public static NewSubscriptionMatrixWithAllocationPrice From( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredPackageWithMinimumPrice( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - > -{ - public static NewSubscriptionTieredPackageWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPrice( - Subscriptions::NewSubscriptionGroupedTieredPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - > -{ - public static NewSubscriptionGroupedTieredPrice From( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParams.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParams.cs index 0b975710..097fb380 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParams.cs @@ -1,7 +1,11 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionFetchCostsParamsProperties = Orb.Models.Subscriptions.SubscriptionFetchCostsParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; @@ -12,104 +16,171 @@ namespace Orb.Models.Subscriptions; /// the [subscription usage endpoint](fetch-subscription-usage) to fetch usage per /// metric, in usage units rather than a currency). /// -/// The semantics of this endpoint exactly mirror those of [fetching a customer's +/// The semantics of this endpoint exactly mirror those of [fetching a customer's /// costs](fetch-customer-costs). Use this endpoint to limit your analysis of costs -/// to a specific subscription for the customer (e.g. to de-aggregate costs when a -/// customer's subscription has started and stopped on the same day). +/// to a specific subscription for the customer (e.g. to de-aggregate costs when +/// a customer's subscription has started and stopped on the same day). /// -public sealed record class SubscriptionFetchCostsParams : Orb::ParamsBase +public sealed record class SubscriptionFetchCostsParams : ParamsBase { - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// The currency or custom pricing unit to use. /// public string? Currency { - get - { - if (!this.QueryProperties.TryGetValue("currency", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["currency"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "currency"); } + init { JsonModel.Set(this._rawQueryData, "currency", value); } } /// /// Costs returned are exclusive of `timeframe_end`. /// - public System::DateTime? TimeframeEnd + public System::DateTimeOffset? TimeframeEnd { get { - if (!this.QueryProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_end" + ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_end", value); } } /// /// Costs returned are inclusive of `timeframe_start`. /// - public System::DateTime? TimeframeStart + public System::DateTimeOffset? TimeframeStart { get { - if (!this.QueryProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_start" ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_start", value); } } /// /// Controls whether Orb returns cumulative costs since the start of the billing - /// period, or incremental day-by-day costs. If your customer has minimums or discounts, - /// it's strongly recommended that you use the default cumulative behavior. + /// period, or incremental day-by-day costs. If your customer has minimums or + /// discounts, it's strongly recommended that you use the default cumulative behavior. /// - public SubscriptionFetchCostsParamsProperties::ViewMode? ViewMode + public ApiEnum? ViewMode { get { - if (!this.QueryProperties.TryGetValue("view_mode", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawQueryData, + "view_mode" ); } - set { this.QueryProperties["view_mode"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "view_mode", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionFetchCostsParams() { } + + public SubscriptionFetchCostsParams(SubscriptionFetchCostsParams subscriptionFetchCostsParams) + : base(subscriptionFetchCostsParams) { } + + public SubscriptionFetchCostsParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionFetchCostsParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionFetchCostsParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/costs", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// Controls whether Orb returns cumulative costs since the start of the billing +/// period, or incremental day-by-day costs. If your customer has minimums or discounts, +/// it's strongly recommended that you use the default cumulative behavior. +/// +[JsonConverter(typeof(ViewModeConverter))] +public enum ViewMode +{ + Periodic, + Cumulative, +} + +sealed class ViewModeConverter : JsonConverter +{ + public override ViewMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "periodic" => ViewMode.Periodic, + "cumulative" => ViewMode.Cumulative, + _ => (ViewMode)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, ViewMode value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + ViewMode.Periodic => "periodic", + ViewMode.Cumulative => "cumulative", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParamsProperties/ViewMode.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParamsProperties/ViewMode.cs deleted file mode 100644 index 22309700..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchCostsParamsProperties/ViewMode.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionFetchCostsParamsProperties; - -/// -/// Controls whether Orb returns cumulative costs since the start of the billing period, -/// or incremental day-by-day costs. If your customer has minimums or discounts, it's -/// strongly recommended that you use the default cumulative behavior. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ViewMode(string value) : Orb::IEnum -{ - public static readonly ViewMode Periodic = new("periodic"); - - public static readonly ViewMode Cumulative = new("cumulative"); - - readonly string _value = value; - - public enum Value - { - Periodic, - Cumulative, - } - - public Value Known() => - _value switch - { - "periodic" => Value.Periodic, - "cumulative" => Value.Cumulative, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ViewMode FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchCostsResponse.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchCostsResponse.cs index a139b9d9..5b337008 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchCostsResponse.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchCostsResponse.cs @@ -1,31 +1,27 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionFetchCostsResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionFetchCostsResponse, + SubscriptionFetchCostsResponseFromRaw + >) +)] +public sealed record class SubscriptionFetchCostsResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -36,18 +32,44 @@ public override void Validate() public SubscriptionFetchCostsResponse() { } + public SubscriptionFetchCostsResponse( + SubscriptionFetchCostsResponse subscriptionFetchCostsResponse + ) + : base(subscriptionFetchCostsResponse) { } + + public SubscriptionFetchCostsResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionFetchCostsResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionFetchCostsResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionFetchCostsResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionFetchCostsResponse(List data) + : this() + { + this.Data = data; } } + +class SubscriptionFetchCostsResponseFromRaw : IFromRawJson +{ + /// + public SubscriptionFetchCostsResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionFetchCostsResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchParams.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchParams.cs index b308870a..f4e167a1 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; @@ -8,27 +12,65 @@ namespace Orb.Models.Subscriptions; /// This endpoint is used to fetch a [Subscription](/core-concepts##subscription) /// given an identifier. /// -public sealed record class SubscriptionFetchParams : Orb::ParamsBase +public sealed record class SubscriptionFetchParams : ParamsBase { - public required string SubscriptionID; + public string? SubscriptionID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionFetchParams() { } + + public SubscriptionFetchParams(SubscriptionFetchParams subscriptionFetchParams) + : base(subscriptionFetchParams) { } + + public SubscriptionFetchParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionFetchParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionFetchParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePage.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePage.cs new file mode 100644 index 00000000..0f8a1cca --- /dev/null +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePage.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Subscriptions; + +public sealed class SubscriptionFetchSchedulePage( + ISubscriptionService service, + SubscriptionFetchScheduleParams parameters, + SubscriptionFetchSchedulePageResponse response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task< + IPage + > IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next( + CancellationToken cancellationToken = default + ) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .FetchSchedule(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponse.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponse.cs index d48e0cc9..ea19bb1b 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponse.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponse.cs @@ -1,52 +1,45 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionFetchSchedulePageResponseProperties = Orb.Models.Subscriptions.SubscriptionFetchSchedulePageResponseProperties; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class SubscriptionFetchSchedulePageResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionFetchSchedulePageResponse, + SubscriptionFetchSchedulePageResponseFromRaw + >) +)] +public sealed record class SubscriptionFetchSchedulePageResponse : JsonModel { - public required Generic::List Data + public required IReadOnlyList Data { get { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "data", value); } } - public required Models::PaginationMetadata PaginationMetadata + public required PaginationMetadata PaginationMetadata { get { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } } + /// public override void Validate() { foreach (var item in this.Data) @@ -58,18 +51,38 @@ public override void Validate() public SubscriptionFetchSchedulePageResponse() { } + public SubscriptionFetchSchedulePageResponse( + SubscriptionFetchSchedulePageResponse subscriptionFetchSchedulePageResponse + ) + : base(subscriptionFetchSchedulePageResponse) { } + + public SubscriptionFetchSchedulePageResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - SubscriptionFetchSchedulePageResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + SubscriptionFetchSchedulePageResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static SubscriptionFetchSchedulePageResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class SubscriptionFetchSchedulePageResponseFromRaw + : IFromRawJson +{ + /// + public SubscriptionFetchSchedulePageResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionFetchSchedulePageResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponseProperties/Data.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponseProperties/Data.cs deleted file mode 100644 index c71ff26f..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponseProperties/Data.cs +++ /dev/null @@ -1,93 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Subscriptions.SubscriptionFetchSchedulePageResponseProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionFetchSchedulePageResponseProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required System::DateTime CreatedAt - { - get - { - if (!this.Properties.TryGetValue("created_at", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "created_at", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["created_at"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DataProperties::Plan? Plan - { - get - { - if (!this.Properties.TryGetValue("plan", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("plan", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["plan"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.CreatedAt; - _ = this.EndDate; - this.Plan?.Validate(); - _ = this.StartDate; - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponseProperties/DataProperties/Plan.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponseProperties/DataProperties/Plan.cs deleted file mode 100644 index 1090ab9d..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchSchedulePageResponseProperties/DataProperties/Plan.cs +++ /dev/null @@ -1,81 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionFetchSchedulePageResponseProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Plan : Orb::ModelBase, Orb::IFromRaw -{ - public required string? ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An optional user-defined ID for this plan resource, used throughout the system - /// as an alias for this Plan. Use this field to identify a plan by an existing - /// identifier in your system. - /// - public required string? ExternalPlanID - { - get - { - if (!this.Properties.TryGetValue("external_plan_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "external_plan_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_plan_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public required string? Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.ExternalPlanID; - _ = this.Name; - } - - public Plan() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Plan(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Plan FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleParams.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleParams.cs index 8be0c2df..31e74012 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleParams.cs @@ -1,7 +1,10 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; @@ -10,9 +13,9 @@ namespace Orb.Models.Subscriptions; /// associated with a subscription along with their start and end dates. This list /// contains the subscription's initial plan along with past and future plan changes. /// -public sealed record class SubscriptionFetchScheduleParams : Orb::ParamsBase +public sealed record class SubscriptionFetchScheduleParams : ParamsBase { - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// Cursor for pagination. This can be populated by the `next_cursor` value returned @@ -20,14 +23,8 @@ public sealed record class SubscriptionFetchScheduleParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } /// @@ -35,97 +32,117 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public System::DateTime? StartDateGt + public DateTimeOffset? StartDateGt { get { - if (!this.QueryProperties.TryGetValue("start_date[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["start_date[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "start_date[gt]"); } + init { JsonModel.Set(this._rawQueryData, "start_date[gt]", value); } } - public System::DateTime? StartDateGte + public DateTimeOffset? StartDateGte { get { - if (!this.QueryProperties.TryGetValue("start_date[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["start_date[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "start_date[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "start_date[gte]", value); } } - public System::DateTime? StartDateLt + public DateTimeOffset? StartDateLt { get { - if (!this.QueryProperties.TryGetValue("start_date[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["start_date[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct(this.RawQueryData, "start_date[lt]"); } + init { JsonModel.Set(this._rawQueryData, "start_date[lt]", value); } } - public System::DateTime? StartDateLte + public DateTimeOffset? StartDateLte { get { - if (!this.QueryProperties.TryGetValue("start_date[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["start_date[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "start_date[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "start_date[lte]", value); } + } + + public SubscriptionFetchScheduleParams() { } + + public SubscriptionFetchScheduleParams( + SubscriptionFetchScheduleParams subscriptionFetchScheduleParams + ) + : base(subscriptionFetchScheduleParams) { } + + public SubscriptionFetchScheduleParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionFetchScheduleParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionFetchScheduleParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/schedule", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleResponse.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleResponse.cs new file mode 100644 index 00000000..977fd57f --- /dev/null +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchScheduleResponse.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; + +namespace Orb.Models.Subscriptions; + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionFetchScheduleResponse, + SubscriptionFetchScheduleResponseFromRaw + >) +)] +public sealed record class SubscriptionFetchScheduleResponse : JsonModel +{ + public required DateTimeOffset CreatedAt + { + get { return JsonModel.GetNotNullStruct(this.RawData, "created_at"); } + init { JsonModel.Set(this._rawData, "created_at", value); } + } + + public required DateTimeOffset? EndDate + { + get { return JsonModel.GetNullableStruct(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + public required Plan? Plan + { + get { return JsonModel.GetNullableClass(this.RawData, "plan"); } + init { JsonModel.Set(this._rawData, "plan", value); } + } + + public required DateTimeOffset StartDate + { + get { return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + public override void Validate() + { + _ = this.CreatedAt; + _ = this.EndDate; + this.Plan?.Validate(); + _ = this.StartDate; + } + + public SubscriptionFetchScheduleResponse() { } + + public SubscriptionFetchScheduleResponse( + SubscriptionFetchScheduleResponse subscriptionFetchScheduleResponse + ) + : base(subscriptionFetchScheduleResponse) { } + + public SubscriptionFetchScheduleResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionFetchScheduleResponse(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionFetchScheduleResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionFetchScheduleResponseFromRaw : IFromRawJson +{ + /// + public SubscriptionFetchScheduleResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionFetchScheduleResponse.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Plan : JsonModel +{ + public required string? ID + { + get { return JsonModel.GetNullableClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + /// + /// An optional user-defined ID for this plan resource, used throughout the system + /// as an alias for this Plan. Use this field to identify a plan by an existing + /// identifier in your system. + /// + public required string? ExternalPlanID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_plan_id"); } + init { JsonModel.Set(this._rawData, "external_plan_id", value); } + } + + public required string? Name + { + get { return JsonModel.GetNullableClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.ExternalPlanID; + _ = this.Name; + } + + public Plan() { } + + public Plan(Plan plan) + : base(plan) { } + + public Plan(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Plan(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Plan FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PlanFromRaw : IFromRawJson +{ + /// + public Plan FromRawUnchecked(IReadOnlyDictionary rawData) => + Plan.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParams.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParams.cs index df201a44..877e2997 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParams.cs @@ -1,7 +1,11 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionFetchUsageParamsProperties = Orb.Models.Subscriptions.SubscriptionFetchUsageParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; @@ -11,132 +15,132 @@ namespace Orb.Models.Subscriptions; /// combined with optional query parameters, this endpoint is a powerful way to build /// visualizations on top of Orb's event data and metrics. /// -/// With no query parameters specified, this endpoint returns usage for the subscription's -/// _current billing period_ across each billable metric that participates in the -/// subscription. Usage quantities returned are the result of evaluating the metric -/// definition for the entirety of the customer's billing period. +/// With no query parameters specified, this endpoint returns usage for the +/// subscription's _current billing period_ across each billable metric that participates +/// in the subscription. Usage quantities returned are the result of evaluating the +/// metric definition for the entirety of the customer's billing period. /// -/// ### Default response shape Orb returns a `data` array with an object corresponding +/// ### Default response shape Orb returns a `data` array with an object corresponding /// to each billable metric. Nested within this object is a `usage` array which has /// a `quantity` value and a corresponding `timeframe_start` and `timeframe_end`. -/// The `quantity` value represents the calculated usage value for the billable -/// metric over the specified timeframe (inclusive of the `timeframe_start` timestamp -/// and exclusive of the `timeframe_end` timestamp). +/// The `quantity` value represents the calculated usage value for the billable metric +/// over the specified timeframe (inclusive of the `timeframe_start` timestamp and +/// exclusive of the `timeframe_end` timestamp). /// -/// Orb will include _every_ window in the response starting from the beginning of -/// the billing period, even when there were no events (and therefore no usage) in -/// the window. This increases the size of the response but prevents the caller from -/// filling in gaps and handling cumbersome time-based logic. +/// Orb will include _every_ window in the response starting from the beginning +/// of the billing period, even when there were no events (and therefore no usage) +/// in the window. This increases the size of the response but prevents the caller +/// from filling in gaps and handling cumbersome time-based logic. /// -/// The query parameters in this endpoint serve to override this behavior and provide -/// some key functionality, as listed below. Note that this functionality can also -/// be used _in conjunction_ with each other, e.g. to display grouped usage on a -/// custom timeframe. +/// The query parameters in this endpoint serve to override this behavior and +/// provide some key functionality, as listed below. Note that this functionality +/// can also be used _in conjunction_ with each other, e.g. to display grouped usage +/// on a custom timeframe. /// -/// ## Custom timeframe In order to view usage for a custom timeframe rather than -/// the current billing period, specify a `timeframe_start` and `timeframe_end`. +/// ## Custom timeframe In order to view usage for a custom timeframe rather +/// than the current billing period, specify a `timeframe_start` and `timeframe_end`. /// This will calculate quantities for usage incurred between timeframe_start (inclusive) -/// and timeframe_end (exclusive), i.e. `[timeframe_start, timeframe_end)`. +/// and timeframe_end (exclusive), i.e. `[timeframe_start, timeframe_end)`. /// -/// Note: - These timestamps must be specified in ISO 8601 format and UTC timezone, -/// e.g. `2022-02-01T05:00:00Z`. - Both parameters must be specified if either is specified. +/// Note: - These timestamps must be specified in ISO 8601 format and UTC timezone, +/// e.g. `2022-02-01T05:00:00Z`. - Both parameters must be specified if either is specified. /// -/// ## Grouping by custom attributes In order to view a single metric grouped by a -/// specific _attribute_ that each event is tagged with (e.g. `cluster`), you must -/// additionally specify a `billable_metric_id` and a `group_by` key. The `group_by` -/// key denotes the event property on which to group. +/// ## Grouping by custom attributes In order to view a single metric grouped +/// by a specific _attribute_ that each event is tagged with (e.g. `cluster`), you +/// must additionally specify a `billable_metric_id` and a `group_by` key. The `group_by` +/// key denotes the event property on which to group. /// -/// When returning grouped usage, only usage for `billable_metric_id` is returned, +/// When returning grouped usage, only usage for `billable_metric_id` is returned, /// and a separate object in the `data` array is returned for each value of the `group_by` -/// key present in your events. The `quantity` value is the result of evaluating -/// the billable metric for events filtered to a single value of the `group_by` key. +/// key present in your events. The `quantity` value is the result of evaluating the +/// billable metric for events filtered to a single value of the `group_by` key. /// -/// Orb expects that events that match the billable metric will contain values in -/// the `properties` dictionary that correspond to the `group_by` key specified. +/// Orb expects that events that match the billable metric will contain values +/// in the `properties` dictionary that correspond to the `group_by` key specified. /// By default, Orb will not return a `null` group (i.e. events that match the metric /// but do not have the key set). Currently, it is only possible to view usage grouped -/// by a single attribute at a time. +/// by a single attribute at a time. /// -/// When viewing grouped usage, Orb uses pagination to limit the response size to -/// 1000 groups by default. If there are more groups for a given subscription, pagination -/// metadata in the response can be used to fetch all of the data. +/// When viewing grouped usage, Orb uses pagination to limit the response size +/// to 1000 groups by default. If there are more groups for a given subscription, +/// pagination metadata in the response can be used to fetch all of the data. /// -/// The following example shows usage for an "API Requests" billable metric grouped -/// by `region`. Note the extra `metric_group` dictionary in the response, which -/// provides metadata about the group: +/// The following example shows usage for an "API Requests" billable metric +/// grouped by `region`. Note the extra `metric_group` dictionary in the response, +/// which provides metadata about the group: /// -/// ```json { "data": [ { "usage": [ { -/// "quantity": 0.19291, "timeframe_start": +/// ```json { "data": [ { "usage": [ +/// { "quantity": 0.19291, "timeframe_start": /// "2021-10-01T07:00:00Z", "timeframe_end": "2021-10-02T07:00:00Z", /// }, ... ], "metric_group": /// { "property_key": "region", "property_value": /// "asia/pacific" }, "billable_metric": { -/// "id": "Fe9pbpMk86xpwdGB", "name": "API Requests" -/// }, "view_mode": "periodic" }, ... ] } ``` +/// "id": "Fe9pbpMk86xpwdGB", "name": "API Requests" +/// }, "view_mode": "periodic" }, ... ] } ``` /// -/// ## Windowed usage The `granularity` parameter can be used to _window_ the usage -/// `quantity` value into periods. When not specified, usage is returned for the -/// entirety of the time range. +/// ## Windowed usage The `granularity` parameter can be used to _window_ the +/// usage `quantity` value into periods. When not specified, usage is returned for +/// the entirety of the time range. /// -/// When `granularity = day` is specified with a timeframe longer than a day, Orb -/// will return a `quantity` value for each full day between `timeframe_start` and -/// `timeframe_end`. Note that the days are demarcated by the _customer's local midnight_. +/// When `granularity = day` is specified with a timeframe longer than a day, +/// Orb will return a `quantity` value for each full day between `timeframe_start` +/// and `timeframe_end`. Note that the days are demarcated by the _customer's local midnight_. /// -/// For example, with `timeframe_start = 2022-02-01T05:00:00Z`, `timeframe_end = 2022-02-04T01:00:00Z` -/// and `granularity=day`, the following windows will be returned for a customer in -/// the `America/Los_Angeles` timezone since local midnight is `08:00` UTC: - `[2022-02-01T05:00:00Z, -/// 2022-02-01T08:00:00Z)` - `[2022-02-01T08:00:00, 2022-02-02T08:00:00Z)` - `[2022-02-02T08:00:00, -/// 2022-02-03T08:00:00Z)` - `[2022-02-03T08:00:00, 2022-02-04T01:00:00Z)` +/// For example, with `timeframe_start = 2022-02-01T05:00:00Z`, `timeframe_end +/// = 2022-02-04T01:00:00Z` and `granularity=day`, the following windows will be +/// returned for a customer in the `America/Los_Angeles` timezone since local midnight +/// is `08:00` UTC: - `[2022-02-01T05:00:00Z, 2022-02-01T08:00:00Z)` - `[2022-02-01T08:00:00, +/// 2022-02-02T08:00:00Z)` - `[2022-02-02T08:00:00, 2022-02-03T08:00:00Z)` - `[2022-02-03T08:00:00, 2022-02-04T01:00:00Z)` /// -/// ```json { "data": [ { "billable_metric": { -/// "id": "Q8w89wjTtBdejXKsm", "name": "API Requests" -/// }, "usage": [ { "quantity": +/// ```json { "data": [ { "billable_metric": { +/// "id": "Q8w89wjTtBdejXKsm", "name": "API Requests" +/// }, "usage": [ { "quantity": /// 0, "timeframe_end": "2022-02-01T08:00:00+00:00", -/// "timeframe_start": "2022-02-01T05:00:00+00:00" }, -/// { +/// "timeframe_start": "2022-02-01T05:00:00+00:00" }, +/// { /// -/// "quantity": 0, "timeframe_end": "2022-02-02T08:00:00+00:00", -/// "timeframe_start": "2022-02-01T08:00:00+00:00" -/// }, { "quantity": 0, -/// "timeframe_end": "2022-02-03T08:00:00+00:00", "timeframe_start": -/// "2022-02-02T08:00:00+00:00" }, { -/// "quantity": 0, "timeframe_end": "2022-02-04T01:00:00+00:00", -/// "timeframe_start": "2022-02-03T08:00:00+00:00" -/// } ], "view_mode": "periodic" }, -/// ... ] } ``` +/// "quantity": 0, "timeframe_end": +/// "2022-02-02T08:00:00+00:00", "timeframe_start": "2022-02-01T08:00:00+00:00" +/// }, { "quantity": 0, +/// "timeframe_end": "2022-02-03T08:00:00+00:00", +/// "timeframe_start": "2022-02-02T08:00:00+00:00" }, +/// { "quantity": 0, "timeframe_end": +/// "2022-02-04T01:00:00+00:00", "timeframe_start": "2022-02-03T08:00:00+00:00" +/// } ], "view_mode": "periodic" +/// }, ... ] } ``` /// -/// ## Decomposable vs. non-decomposable metrics Billable metrics fall into one of -/// two categories: decomposable and non-decomposable. A decomposable billable metric, -/// such as a sum or a count, can be displayed and aggregated across arbitrary timescales. -/// On the other hand, a non-decomposable metric is not meaningful when only a slice -/// of the billing window is considered. +/// ## Decomposable vs. non-decomposable metrics Billable metrics fall into +/// one of two categories: decomposable and non-decomposable. A decomposable billable +/// metric, such as a sum or a count, can be displayed and aggregated across arbitrary +/// timescales. On the other hand, a non-decomposable metric is not meaningful when +/// only a slice of the billing window is considered. /// -/// As an example, if we have a billable metric that's defined to count unique users, -/// displaying a graph of unique users for each day is not representative of the -/// billable metric value over the month (days could have an overlapping set of 'unique' -/// users). Instead, what's useful for any given day is the number of unique users -/// in the billing period so far, which are the _cumulative_ unique users. +/// As an example, if we have a billable metric that's defined to count unique +/// users, displaying a graph of unique users for each day is not representative of +/// the billable metric value over the month (days could have an overlapping set of +/// 'unique' users). Instead, what's useful for any given day is the number of unique +/// users in the billing period so far, which are the _cumulative_ unique users. /// -/// Accordingly, this endpoint returns treats these two types of metrics differently +/// Accordingly, this endpoint returns treats these two types of metrics differently /// when `group_by` is specified: - Decomposable metrics can be grouped by any event /// property. - Non-decomposable metrics can only be grouped by the corresponding /// price's invoice grouping key. If no invoice grouping key is present, the metric -/// does not support `group_by`. +/// does not support `group_by`. /// -/// ## Matrix prices When a billable metric is attached to a price that uses matrix -/// pricing, it's important to view usage grouped by those matrix dimensions. In -/// this case, use the query parameters `first_dimension_key`, `first_dimension_value` -/// and `second_dimension_key`, `second_dimension_value` while filtering to a specific `billable_metric_id`. +/// ## Matrix prices When a billable metric is attached to a price that uses +/// matrix pricing, it's important to view usage grouped by those matrix dimensions. +/// In this case, use the query parameters `first_dimension_key`, `first_dimension_value` +/// and `second_dimension_key`, `second_dimension_value` while filtering to a specific `billable_metric_id`. /// -/// For example, if your compute metric has a separate unit price (i.e. a matrix pricing -/// model) per `region` and `provider`, your request might provide the following parameters: +/// For example, if your compute metric has a separate unit price (i.e. a matrix +/// pricing model) per `region` and `provider`, your request might provide the following parameters: /// -/// - `first_dimension_key`: `region` - `first_dimension_value`: `us-east-1` - `second_dimension_key`: -/// `provider` - `second_dimension_value`: `aws` +/// - `first_dimension_key`: `region` - `first_dimension_value`: `us-east-1` +/// - `second_dimension_key`: `provider` - `second_dimension_value`: `aws` /// -public sealed record class SubscriptionFetchUsageParams : Orb::ParamsBase +public sealed record class SubscriptionFetchUsageParams : ParamsBase { - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// When specified in conjunction with `group_by`, this parameter filters usage @@ -145,88 +149,38 @@ public sealed record class SubscriptionFetchUsageParams : Orb::ParamsBase /// public string? BillableMetricID { - get - { - if ( - !this.QueryProperties.TryGetValue( - "billable_metric_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["billable_metric_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "billable_metric_id"); } + init { JsonModel.Set(this._rawQueryData, "billable_metric_id", value); } } public string? FirstDimensionKey { - get - { - if ( - !this.QueryProperties.TryGetValue( - "first_dimension_key", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["first_dimension_key"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawQueryData, "first_dimension_key"); } + init { JsonModel.Set(this._rawQueryData, "first_dimension_key", value); } } public string? FirstDimensionValue { get { - if ( - !this.QueryProperties.TryGetValue( - "first_dimension_value", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["first_dimension_value"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawQueryData, "first_dimension_value"); } + init { JsonModel.Set(this._rawQueryData, "first_dimension_value", value); } } /// /// This determines the windowing of usage reporting. /// - public SubscriptionFetchUsageParamsProperties::Granularity? Granularity + public ApiEnum? Granularity { get { - if (!this.QueryProperties.TryGetValue("granularity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawQueryData, + "granularity" ); } - set - { - this.QueryProperties["granularity"] = Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawQueryData, "granularity", value); } } /// @@ -234,133 +188,223 @@ public string? FirstDimensionValue /// public string? GroupBy { - get - { - if (!this.QueryProperties.TryGetValue("group_by", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["group_by"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "group_by"); } + init { JsonModel.Set(this._rawQueryData, "group_by", value); } } public string? SecondDimensionKey { get { - if ( - !this.QueryProperties.TryGetValue( - "second_dimension_key", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["second_dimension_key"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawQueryData, "second_dimension_key"); } + init { JsonModel.Set(this._rawQueryData, "second_dimension_key", value); } } public string? SecondDimensionValue { get { - if ( - !this.QueryProperties.TryGetValue( - "second_dimension_value", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["second_dimension_value"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass(this.RawQueryData, "second_dimension_value"); } + init { JsonModel.Set(this._rawQueryData, "second_dimension_value", value); } } /// /// Usage returned is exclusive of `timeframe_end`. /// - public System::DateTime? TimeframeEnd + public System::DateTimeOffset? TimeframeEnd { get { - if (!this.QueryProperties.TryGetValue("timeframe_end", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_end" + ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_end", value); } } /// /// Usage returned is inclusive of `timeframe_start`. /// - public System::DateTime? TimeframeStart + public System::DateTimeOffset? TimeframeStart { get { - if (!this.QueryProperties.TryGetValue("timeframe_start", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["timeframe_start"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "timeframe_start" ); } + init { JsonModel.Set(this._rawQueryData, "timeframe_start", value); } } /// /// Controls whether Orb returns cumulative usage since the start of the billing - /// period, or incremental day-by-day usage. If your customer has minimums or discounts, - /// it's strongly recommended that you use the default cumulative behavior. + /// period, or incremental day-by-day usage. If your customer has minimums or + /// discounts, it's strongly recommended that you use the default cumulative behavior. /// - public SubscriptionFetchUsageParamsProperties::ViewMode? ViewMode + public ApiEnum? ViewMode { get { - if (!this.QueryProperties.TryGetValue("view_mode", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawQueryData, "view_mode"); } - set { this.QueryProperties["view_mode"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "view_mode", value); } + } + + public SubscriptionFetchUsageParams() { } + + public SubscriptionFetchUsageParams(SubscriptionFetchUsageParams subscriptionFetchUsageParams) + : base(subscriptionFetchUsageParams) { } + + public SubscriptionFetchUsageParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionFetchUsageParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionFetchUsageParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/usage", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// This determines the windowing of usage reporting. +/// +[JsonConverter(typeof(GranularityConverter))] +public enum Granularity +{ + Day, +} + +sealed class GranularityConverter : JsonConverter +{ + public override Granularity Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "day" => Granularity.Day, + _ => (Granularity)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + Granularity value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + Granularity.Day => "day", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Controls whether Orb returns cumulative usage since the start of the billing +/// period, or incremental day-by-day usage. If your customer has minimums or discounts, +/// it's strongly recommended that you use the default cumulative behavior. +/// +[JsonConverter(typeof(SubscriptionFetchUsageParamsViewModeConverter))] +public enum SubscriptionFetchUsageParamsViewMode +{ + Periodic, + Cumulative, +} + +sealed class SubscriptionFetchUsageParamsViewModeConverter + : JsonConverter +{ + public override SubscriptionFetchUsageParamsViewMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "periodic" => SubscriptionFetchUsageParamsViewMode.Periodic, + "cumulative" => SubscriptionFetchUsageParamsViewMode.Cumulative, + _ => (SubscriptionFetchUsageParamsViewMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionFetchUsageParamsViewMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionFetchUsageParamsViewMode.Periodic => "periodic", + SubscriptionFetchUsageParamsViewMode.Cumulative => "cumulative", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParamsProperties/Granularity.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParamsProperties/Granularity.cs deleted file mode 100644 index 851e46c2..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParamsProperties/Granularity.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionFetchUsageParamsProperties; - -/// -/// This determines the windowing of usage reporting. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Granularity(string value) : Orb::IEnum -{ - public static readonly Granularity Day = new("day"); - - readonly string _value = value; - - public enum Value - { - Day, - } - - public Value Known() => - _value switch - { - "day" => Value.Day, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Granularity FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParamsProperties/ViewMode.cs b/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParamsProperties/ViewMode.cs deleted file mode 100644 index bfd7833a..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionFetchUsageParamsProperties/ViewMode.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionFetchUsageParamsProperties; - -/// -/// Controls whether Orb returns cumulative usage since the start of the billing period, -/// or incremental day-by-day usage. If your customer has minimums or discounts, it's -/// strongly recommended that you use the default cumulative behavior. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ViewMode(string value) : Orb::IEnum -{ - public static readonly ViewMode Periodic = new("periodic"); - - public static readonly ViewMode Cumulative = new("cumulative"); - - readonly string _value = value; - - public enum Value - { - Periodic, - Cumulative, - } - - public Value Known() => - _value switch - { - "periodic" => Value.Periodic, - "cumulative" => Value.Cumulative, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ViewMode FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionListPage.cs b/src/Orb/Models/Subscriptions/SubscriptionListPage.cs new file mode 100644 index 00000000..3a8d879a --- /dev/null +++ b/src/Orb/Models/Subscriptions/SubscriptionListPage.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; + +namespace Orb.Models.Subscriptions; + +public sealed class SubscriptionListPage( + ISubscriptionService service, + SubscriptionListParams parameters, + SubscriptionSubscriptions response +) : IPage +{ + /// + public IReadOnlyList Items + { + get { return response.Data; } + } + + /// + public bool HasNext() + { + try + { + return this.Items.Count > 0 && response.PaginationMetadata.NextCursor != null; + } + catch (OrbInvalidDataException) + { + // If accessing the response data to determine if there's a next page failed, then just + // assume there's no next page. + return false; + } + } + + /// + async Task> IPage.Next(CancellationToken cancellationToken) => + await this.Next(cancellationToken).ConfigureAwait(false); + + /// + public async Task Next(CancellationToken cancellationToken = default) + { + var nextCursor = + response.PaginationMetadata.NextCursor + ?? throw new InvalidOperationException("Cannot request next page"); + return await service + .List(parameters with { Cursor = nextCursor }, cancellationToken) + .ConfigureAwait(false); + } + + /// + public void Validate() + { + response.Validate(); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionListParams.cs b/src/Orb/Models/Subscriptions/SubscriptionListParams.cs index b14b7bc5..bf706e56 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionListParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionListParams.cs @@ -1,8 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionListParamsProperties = Orb.Models.Subscriptions.SubscriptionListParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; namespace Orb.Models.Subscriptions; @@ -12,74 +15,58 @@ namespace Orb.Models.Subscriptions; /// list, ordered starting from the most recently created subscription. For a full /// discussion of the subscription resource, see [Subscription](/core-concepts##subscription). /// -/// Subscriptions can be filtered for a specific customer by using either the customer_id -/// or external_customer_id query parameters. To filter subscriptions for multiple -/// customers, use the customer_id[] or external_customer_id[] query parameters. +/// Subscriptions can be filtered for a specific customer by using either the +/// customer_id or external_customer_id query parameters. To filter subscriptions +/// for multiple customers, use the customer_id[] or external_customer_id[] query parameters. /// -public sealed record class SubscriptionListParams : Orb::ParamsBase +public sealed record class SubscriptionListParams : ParamsBase { - public System::DateTime? CreatedAtGt + public System::DateTimeOffset? CreatedAtGt { get { - if (!this.QueryProperties.TryGetValue("created_at[gt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gt]", value); } } - public System::DateTime? CreatedAtGte + public System::DateTimeOffset? CreatedAtGte { get { - if (!this.QueryProperties.TryGetValue("created_at[gte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[gte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[gte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[gte]", value); } } - public System::DateTime? CreatedAtLt + public System::DateTimeOffset? CreatedAtLt { get { - if (!this.QueryProperties.TryGetValue("created_at[lt]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lt]"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lt]" + ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lt]", value); } } - public System::DateTime? CreatedAtLte + public System::DateTimeOffset? CreatedAtLte { get { - if (!this.QueryProperties.TryGetValue("created_at[lte]", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.QueryProperties["created_at[lte]"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableStruct( + this.RawQueryData, + "created_at[lte]" ); } + init { JsonModel.Set(this._rawQueryData, "created_at[lte]", value); } } /// @@ -88,51 +75,32 @@ public sealed record class SubscriptionListParams : Orb::ParamsBase /// public string? Cursor { - get - { - if (!this.QueryProperties.TryGetValue("cursor", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.QueryProperties["cursor"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawQueryData, "cursor"); } + init { JsonModel.Set(this._rawQueryData, "cursor", value); } } - public Generic::List? CustomerID + public IReadOnlyList? CustomerID { - get - { - if (!this.QueryProperties.TryGetValue("customer_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.QueryProperties["customer_id"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass>(this.RawQueryData, "customer_id"); } + init { JsonModel.Set(this._rawQueryData, "customer_id", value); } } - public Generic::List? ExternalCustomerID + public IReadOnlyList? ExternalCustomerID { get { - if ( - !this.QueryProperties.TryGetValue( - "external_customer_id", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.QueryProperties["external_customer_id"] = Json::JsonSerializer.SerializeToElement( - value + return JsonModel.GetNullableClass>( + this.RawQueryData, + "external_customer_id" ); } + init { JsonModel.Set(this._rawQueryData, "external_customer_id", value); } + } + + public string? ExternalPlanID + { + get { return JsonModel.GetNullableClass(this.RawQueryData, "external_plan_id"); } + init { JsonModel.Set(this._rawQueryData, "external_plan_id", value); } } /// @@ -140,44 +108,134 @@ public string? Cursor /// public long? Limit { - get + get { return JsonModel.GetNullableStruct(this.RawQueryData, "limit"); } + init { - if (!this.QueryProperties.TryGetValue("limit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawQueryData, "limit", value); } - set { this.QueryProperties["limit"] = Json::JsonSerializer.SerializeToElement(value); } } - public SubscriptionListParamsProperties::Status? Status + public string? PlanID + { + get { return JsonModel.GetNullableClass(this.RawQueryData, "plan_id"); } + init { JsonModel.Set(this._rawQueryData, "plan_id", value); } + } + + public ApiEnum? Status { get { - if (!this.QueryProperties.TryGetValue("status", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawQueryData, "status"); } - set { this.QueryProperties["status"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawQueryData, "status", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionListParams() { } + + public SubscriptionListParams(SubscriptionListParams subscriptionListParams) + : base(subscriptionListParams) { } + + public SubscriptionListParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/subscriptions") + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionListParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionListParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/subscriptions") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter(typeof(global::Orb.Models.Subscriptions.StatusConverter))] +public enum Status +{ + Active, + Ended, + Upcoming, +} + +sealed class StatusConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.Status Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "active" => global::Orb.Models.Subscriptions.Status.Active, + "ended" => global::Orb.Models.Subscriptions.Status.Ended, + "upcoming" => global::Orb.Models.Subscriptions.Status.Upcoming, + _ => (global::Orb.Models.Subscriptions.Status)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.Status value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + global::Orb.Models.Subscriptions.Status.Active => "active", + global::Orb.Models.Subscriptions.Status.Ended => "ended", + global::Orb.Models.Subscriptions.Status.Upcoming => "upcoming", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionListParamsProperties/Status.cs b/src/Orb/Models/Subscriptions/SubscriptionListParamsProperties/Status.cs deleted file mode 100644 index a9682818..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionListParamsProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionListParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Ended = new("ended"); - - public static readonly Status Upcoming = new("upcoming"); - - readonly string _value = value; - - public enum Value - { - Active, - Ended, - Upcoming, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "ended" => Value.Ended, - "upcoming" => Value.Upcoming, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParams.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParams.cs index e2cac143..ffc992be 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionPriceIntervalsParamsProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; @@ -13,110 +16,117 @@ namespace Orb.Models.Subscriptions; /// By making modifications to a subscription’s price intervals, you can [flexibly /// and atomically control the billing behavior of a subscription](/product-catalog/modifying-subscriptions). /// -/// ## Adding price intervals +/// ## Adding price intervals /// -/// Prices can be added as price intervals to a subscription by specifying them in -/// the `add` array. A `price_id` or `external_price_id` from an add-on price or previously -/// removed plan price can be specified to reuse an existing price definition (however, -/// please note that prices from other plans cannot be added to the subscription). -/// Additionally, a new price can be specified using the `price` field — this price -/// will be created automatically. +/// Prices can be added as price intervals to a subscription by specifying +/// them in the `add` array. A `price_id` or `external_price_id` from an add-on price +/// or previously removed plan price can be specified to reuse an existing price +/// definition (however, please note that prices from other plans cannot be added +/// to the subscription). Additionally, a new price can be specified using the `price` +/// field — this price will be created automatically. /// -/// A `start_date` must be specified for the price interval. This is the date when -/// the price will start billing on the subscription, so this will notably result +/// A `start_date` must be specified for the price interval. This is the date +/// when the price will start billing on the subscription, so this will notably result /// in an immediate charge at this time for any billed in advance fixed fees. The /// `end_date` will default to null, resulting in a price interval that will bill -/// on a continually recurring basis. Both of these dates can be set in the past or -/// the future and Orb will generate or modify invoices to ensure the subscription’s -/// invoicing behavior is correct. +/// on a continually recurring basis. Both of these dates can be set in the past +/// or the future and Orb will generate or modify invoices to ensure the subscription’s +/// invoicing behavior is correct. /// -/// Additionally, a discount, minimum, or maximum can be specified on the price interval. -/// This will only apply to this price interval, not any other price intervals on -/// the subscription. +/// Additionally, a discount, minimum, or maximum can be specified on the price +/// interval. This will only apply to this price interval, not any other price intervals +/// on the subscription. /// -/// ## Adjustment intervals +/// ## Adjustment intervals /// -/// An adjustment interval represents the time period that a particular adjustment +/// An adjustment interval represents the time period that a particular adjustment /// (a discount, minimum, or maximum) applies to the prices on a subscription. Adjustment /// intervals can be added to a subscription by specifying them in the `add_adjustments` /// array, or modified via the `edit_adjustments` array. When creating an adjustment /// interval, you'll need to provide the definition of the new adjustment (the type -/// of adjustment, and which prices it applies to), as well as the start and end dates -/// for the adjustment interval. The start and end dates of an existing adjustment +/// of adjustment, and which prices it applies to), as well as the start and end +/// dates for the adjustment interval. The start and end dates of an existing adjustment /// interval can be edited via the `edit_adjustments` field (just like price intervals). /// (To "change" the amount of a discount, minimum, or maximum, then, you'll need /// to end the existing interval, and create a new adjustment interval with the new -/// amount and a start date that matches the end date of the previous interval.) +/// amount and a start date that matches the end date of the previous interval.) /// -/// ## Editing price intervals +/// ## Editing price intervals /// -/// Price intervals can be adjusted by specifying edits to make in the `edit` array. -/// A `price_interval_id` to edit must be specified — this can be retrieved from -/// the `price_intervals` field on the subscription. +/// Price intervals can be adjusted by specifying edits to make in the `edit` +/// array. A `price_interval_id` to edit must be specified — this can be retrieved +/// from the `price_intervals` field on the subscription. /// -/// A new `start_date` or `end_date` can be specified to change the range of the price -/// interval, which will modify past or future invoices to ensure correctness. If -/// either of these dates are unspecified, they will default to the existing date +/// A new `start_date` or `end_date` can be specified to change the range of +/// the price interval, which will modify past or future invoices to ensure correctness. +/// If either of these dates are unspecified, they will default to the existing date /// on the price interval. To remove a price interval entirely from a subscription, -/// set the `end_date` to be equivalent to the `start_date`. +/// set the `end_date` to be equivalent to the `start_date`. /// -/// ## Fixed fee quantity transitions The fixed fee quantity transitions for a fixed -/// fee price interval can also be specified when adding or editing by passing an -/// array for `fixed_fee_quantity_transitions`. A fixed fee quantity transition must -/// have a `quantity` and an `effective_date`, which is the date after which the -/// new quantity will be used for billing. If a fixed fee quantity transition is -/// scheduled at a billing period boundary, the full quantity will be billed on an -/// invoice with the other prices on the subscription. If the fixed fee quantity transition -/// is scheduled mid-billing period, the difference between the existing quantity -/// and quantity specified in the transition will be prorated for the rest of the -/// billing period and billed immediately, which will generate a new invoice. +/// ## Fixed fee quantity transitions The fixed fee quantity transitions for +/// a fixed fee price interval can also be specified when adding or editing by passing +/// an array for `fixed_fee_quantity_transitions`. A fixed fee quantity transition +/// must have a `quantity` and an `effective_date`, which is the date after which +/// the new quantity will be used for billing. If a fixed fee quantity transition +/// is scheduled at a billing period boundary, the full quantity will be billed on +/// an invoice with the other prices on the subscription. If the fixed fee quantity +/// transition is scheduled mid-billing period, the difference between the existing +/// quantity and quantity specified in the transition will be prorated for the rest +/// of the billing period and billed immediately, which will generate a new invoice. /// -/// Notably, the list of fixed fee quantity transitions passed will overwrite the -/// existing fixed fee quantity transitions on the price interval, so the entire list -/// of transitions must be specified to add additional transitions. The existing list -/// of transitions can be retrieved using the `fixed_fee_quantity_transitions` property -/// on a subscription’s serialized price intervals. +/// Notably, the list of fixed fee quantity transitions passed will overwrite +/// the existing fixed fee quantity transitions on the price interval, so the entire +/// list of transitions must be specified to add additional transitions. The existing +/// list of transitions can be retrieved using the `fixed_fee_quantity_transitions` +/// property on a subscription’s serialized price intervals. /// -public sealed record class SubscriptionPriceIntervalsParams : Orb::ParamsBase +public sealed record class SubscriptionPriceIntervalsParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// A list of price intervals to add to the subscription. /// - public Generic::List? Add + public IReadOnlyList? Add { - get + get { return JsonModel.GetNullableClass>(this.RawBodyData, "add"); } + init { - if (!this.BodyProperties.TryGetValue("add", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize?>( - element - ); + JsonModel.Set(this._rawBodyData, "add", value); } - set { this.BodyProperties["add"] = Json::JsonSerializer.SerializeToElement(value); } } /// /// A list of adjustments to add to the subscription. /// - public Generic::List? AddAdjustments + public IReadOnlyList? AddAdjustments { get { - if (!this.BodyProperties.TryGetValue("add_adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "add_adjustments" ); } - set + init { - this.BodyProperties["add_adjustments"] = Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "add_adjustments", value); } } @@ -129,88 +139,10164 @@ public bool? AllowInvoiceCreditOrVoid { get { - if ( - !this.BodyProperties.TryGetValue( - "allow_invoice_credit_or_void", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["allow_invoice_credit_or_void"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "allow_invoice_credit_or_void" + ); } + init { JsonModel.Set(this._rawBodyData, "allow_invoice_credit_or_void", value); } + } + + /// + /// If set, the default value to use for added/edited price intervals with an + /// end_date set. + /// + public bool? CanDeferBilling + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "can_defer_billing"); } + init { JsonModel.Set(this._rawBodyData, "can_defer_billing", value); } } /// /// A list of price intervals to edit on the subscription. /// - public Generic::List? Edit + public IReadOnlyList? Edit { - get + get { return JsonModel.GetNullableClass>(this.RawBodyData, "edit"); } + init { - if (!this.BodyProperties.TryGetValue("edit", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize?>( - element - ); + JsonModel.Set(this._rawBodyData, "edit", value); } - set { this.BodyProperties["edit"] = Json::JsonSerializer.SerializeToElement(value); } } /// /// A list of adjustments to edit on the subscription. /// - public Generic::List? EditAdjustments + public IReadOnlyList? EditAdjustments { get { - if (!this.BodyProperties.TryGetValue("edit_adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "edit_adjustments" ); } - set + init { - this.BodyProperties["edit_adjustments"] = Json::JsonSerializer.SerializeToElement( - value - ); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "edit_adjustments", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionPriceIntervalsParams() { } + + public SubscriptionPriceIntervalsParams( + SubscriptionPriceIntervalsParams subscriptionPriceIntervalsParams + ) + : base(subscriptionPriceIntervalsParams) + { + this._rawBodyData = [.. subscriptionPriceIntervalsParams._rawBodyData]; + } + + public SubscriptionPriceIntervalsParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionPriceIntervalsParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionPriceIntervalsParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/price_intervals", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Add : JsonModel +{ + /// + /// The start date of the price interval. This is the date that the price will + /// start billing on the subscription. + /// + public required StartDate StartDate + { + get { return JsonModel.GetNotNullClass(this.RawData, "start_date"); } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + /// The definition of a new allocation price to create and add to the subscription. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// If true, an in-arrears price interval ending mid-cycle will defer billing + /// the final line item until the next scheduled invoice. If false, it will be + /// billed on its end date. + /// + public bool? CanDeferBilling + { + get { return JsonModel.GetNullableStruct(this.RawData, "can_defer_billing"); } + init { JsonModel.Set(this._rawData, "can_defer_billing", value); } + } + + /// + /// A list of discounts to initialize on the price interval. + /// + public IReadOnlyList? Discounts + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "discounts" + ); + } + init { JsonModel.Set(this._rawData, "discounts", value); } + } + + /// + /// The end date of the price interval. This is the date that the price will stop + /// billing on the subscription. + /// + public EndDate? EndDate + { + get { return JsonModel.GetNullableClass(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// The external price id of the price to add to the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// An additional filter to apply to usage queries. This filter must be expressed + /// as a boolean [computed property](/extensibility/advanced-metrics#computed-properties). + /// If null, usage queries will not include any additional filter. + /// + public string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// A list of fixed fee quantity transitions to initialize on the price interval. + /// + public IReadOnlyList? FixedFeeQuantityTransitions + { + get + { + return JsonModel.GetNullableClass< + List + >(this.RawData, "fixed_fee_quantity_transitions"); + } + init { JsonModel.Set(this._rawData, "fixed_fee_quantity_transitions", value); } + } + + /// + /// The maximum amount that will be billed for this price interval for a given + /// billing period. + /// + public double? MaximumAmount + { + get { return JsonModel.GetNullableStruct(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// The minimum amount that will be billed for this price interval for a given + /// billing period. + /// + public double? MinimumAmount + { + get { return JsonModel.GetNullableStruct(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// New floating price request body params. + /// + public PriceModel? Price + { + get { return JsonModel.GetNullableClass(this.RawData, "price"); } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// The id of the price to add to the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + /// A list of customer IDs whose usage events will be aggregated and billed under + /// this subscription. By default, a subscription only considers usage events + /// associated with its attached customer's customer_id. When usage_customer_ids + /// is provided, the subscription includes usage events from the specified customers + /// only. Provided usage_customer_ids must be either the customer for this subscription + /// itself, or any of that customer's children. + /// + public IReadOnlyList? UsageCustomerIDs + { + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } + } + + /// + public override void Validate() + { + this.StartDate.Validate(); + this.AllocationPrice?.Validate(); + _ = this.CanDeferBilling; + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + this.EndDate?.Validate(); + _ = this.ExternalPriceID; + _ = this.Filter; + foreach (var item in this.FixedFeeQuantityTransitions ?? []) + { + item.Validate(); + } + _ = this.MaximumAmount; + _ = this.MinimumAmount; + this.Price?.Validate(); + _ = this.PriceID; + _ = this.UsageCustomerIDs; + } + + public Add() { } + + public Add(Add add) + : base(add) { } + + public Add(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Add(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Add FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Add(StartDate startDate) + : this() + { + this.StartDate = startDate; + } +} + +class AddFromRaw : IFromRawJson +{ + /// + public Add FromRawUnchecked(IReadOnlyDictionary rawData) => + Add.FromRawUnchecked(rawData); +} + +/// +/// The start date of the price interval. This is the date that the price will start +/// billing on the subscription. +/// +[JsonConverter(typeof(StartDateConverter))] +public record class StartDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public StartDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public StartDate(ApiEnum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public StartDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of StartDate"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of StartDate"), + }; + } + + public static implicit operator StartDate(System::DateTimeOffset value) => new(value); + + public static implicit operator StartDate(ApiEnum value) => + new(value); + + public static implicit operator StartDate(BillingCycleRelativeDate value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of StartDate"); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(StartDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class StartDateConverter : JsonConverter +{ + public override StartDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + StartDate value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(DiscountConverter))] +public record class Discount +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public JsonElement DiscountType { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + get { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + return Match( + amount: (x) => x.DiscountType, + percentage: (x) => x.DiscountType, + usage: (x) => x.DiscountType + ); } } + + public Discount(Amount value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Discount(Percentage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Discount(Usage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Discount(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAmount(out var value)) { + /// // `value` is of type `Amount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAmount([NotNullWhen(true)] out Amount? value) + { + value = this.Value as Amount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercentage(out var value)) { + /// // `value` is of type `Percentage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercentage([NotNullWhen(true)] out Percentage? value) + { + value = this.Value as Percentage; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUsage(out var value)) { + /// // `value` is of type `Usage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUsage([NotNullWhen(true)] out Usage? value) + { + value = this.Value as Usage; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (Amount value) => {...}, + /// (Percentage value) => {...}, + /// (Usage value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action amount, + System::Action percentage, + System::Action usage + ) + { + switch (this.Value) + { + case Amount value: + amount(value); + break; + case Percentage value: + percentage(value); + break; + case Usage value: + usage(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of Discount"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (Amount value) => {...}, + /// (Percentage value) => {...}, + /// (Usage value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func amount, + System::Func percentage, + System::Func usage + ) + { + return this.Value switch + { + Amount value => amount(value), + Percentage value => percentage(value), + Usage value => usage(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of Discount"), + }; + } + + public static implicit operator global::Orb.Models.Subscriptions.Discount(Amount value) => + new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Discount(Percentage value) => + new(value); + + public static implicit operator global::Orb.Models.Subscriptions.Discount(Usage value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of Discount"); + } + this.Switch( + (amount) => amount.Validate(), + (percentage) => percentage.Validate(), + (usage) => usage.Validate() + ); + } + + public virtual bool Equals(global::Orb.Models.Subscriptions.Discount? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class DiscountConverter : JsonConverter +{ + public override global::Orb.Models.Subscriptions.Discount? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? discountType; + try + { + discountType = element.GetProperty("discount_type").GetString(); + } + catch + { + discountType = null; + } + + switch (discountType) + { + case "amount": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percentage": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new global::Orb.Models.Subscriptions.Discount(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + global::Orb.Models.Subscriptions.Discount value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Amount : JsonModel +{ + /// + /// Only available if discount_type is `amount`. + /// + public required double AmountDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "amount_discount"); } + init { JsonModel.Set(this._rawData, "amount_discount", value); } + } + + public JsonElement DiscountType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "discount_type"); } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + /// + public override void Validate() + { + _ = this.AmountDiscount; + if ( + !JsonElement.DeepEquals( + this.DiscountType, + JsonSerializer.Deserialize("\"amount\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + } + + public Amount() + { + this.DiscountType = JsonSerializer.Deserialize("\"amount\""); + } + + public Amount(Amount amount) + : base(amount) { } + + public Amount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.DiscountType = JsonSerializer.Deserialize("\"amount\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Amount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Amount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Amount(double amountDiscount) + : this() + { + this.AmountDiscount = amountDiscount; + } +} + +class AmountFromRaw : IFromRawJson +{ + /// + public Amount FromRawUnchecked(IReadOnlyDictionary rawData) => + Amount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Percentage : JsonModel +{ + public JsonElement DiscountType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "discount_type"); } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + /// + /// Only available if discount_type is `percentage`. This is a number between + /// 0 and 1. + /// + public required double PercentageDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percentage_discount"); } + init { JsonModel.Set(this._rawData, "percentage_discount", value); } + } + + /// + public override void Validate() + { + if ( + !JsonElement.DeepEquals( + this.DiscountType, + JsonSerializer.Deserialize("\"percentage\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.PercentageDiscount; + } + + public Percentage() + { + this.DiscountType = JsonSerializer.Deserialize("\"percentage\""); + } + + public Percentage(Percentage percentage) + : base(percentage) { } + + public Percentage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.DiscountType = JsonSerializer.Deserialize("\"percentage\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Percentage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Percentage FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Percentage(double percentageDiscount) + : this() + { + this.PercentageDiscount = percentageDiscount; + } +} + +class PercentageFromRaw : IFromRawJson +{ + /// + public Percentage FromRawUnchecked(IReadOnlyDictionary rawData) => + Percentage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Usage : JsonModel +{ + public JsonElement DiscountType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "discount_type"); } + init { JsonModel.Set(this._rawData, "discount_type", value); } + } + + /// + /// Only available if discount_type is `usage`. Number of usage units that this + /// discount is for. + /// + public required double UsageDiscount + { + get { return JsonModel.GetNotNullStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } + } + + /// + public override void Validate() + { + if ( + !JsonElement.DeepEquals( + this.DiscountType, + JsonSerializer.Deserialize("\"usage\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.UsageDiscount; + } + + public Usage() + { + this.DiscountType = JsonSerializer.Deserialize("\"usage\""); + } + + public Usage(Usage usage) + : base(usage) { } + + public Usage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.DiscountType = JsonSerializer.Deserialize("\"usage\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Usage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Usage FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Usage(double usageDiscount) + : this() + { + this.UsageDiscount = usageDiscount; + } +} + +class UsageFromRaw : IFromRawJson +{ + /// + public Usage FromRawUnchecked(IReadOnlyDictionary rawData) => + Usage.FromRawUnchecked(rawData); +} + +/// +/// The end date of the price interval. This is the date that the price will stop +/// billing on the subscription. +/// +[JsonConverter(typeof(EndDateConverter))] +public record class EndDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EndDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EndDate(ApiEnum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EndDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of EndDate"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of EndDate"), + }; + } + + public static implicit operator EndDate(System::DateTimeOffset value) => new(value); + + public static implicit operator EndDate(ApiEnum value) => + new(value); + + public static implicit operator EndDate(BillingCycleRelativeDate value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of EndDate"); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(EndDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EndDateConverter : JsonConverter +{ + public override EndDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write(Utf8JsonWriter writer, EndDate? value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + global::Orb.Models.Subscriptions.FixedFeeQuantityTransition, + global::Orb.Models.Subscriptions.FixedFeeQuantityTransitionFromRaw + >) +)] +public sealed record class FixedFeeQuantityTransition : JsonModel +{ + /// + /// The date that the fixed fee quantity transition should take effect. + /// + public required System::DateTimeOffset EffectiveDate + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "effective_date" + ); + } + init { JsonModel.Set(this._rawData, "effective_date", value); } + } + + /// + /// The quantity of the fixed fee quantity transition. + /// + public required long Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + public override void Validate() + { + _ = this.EffectiveDate; + _ = this.Quantity; + } + + public FixedFeeQuantityTransition() { } + + public FixedFeeQuantityTransition( + global::Orb.Models.Subscriptions.FixedFeeQuantityTransition fixedFeeQuantityTransition + ) + : base(fixedFeeQuantityTransition) { } + + public FixedFeeQuantityTransition(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + FixedFeeQuantityTransition(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static global::Orb.Models.Subscriptions.FixedFeeQuantityTransition FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class FixedFeeQuantityTransitionFromRaw + : IFromRawJson +{ + /// + public global::Orb.Models.Subscriptions.FixedFeeQuantityTransition FromRawUnchecked( + IReadOnlyDictionary rawData + ) => global::Orb.Models.Subscriptions.FixedFeeQuantityTransition.FromRawUnchecked(rawData); +} + +/// +/// New floating price request body params. +/// +[JsonConverter(typeof(PriceModelConverter))] +public record class PriceModel +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string Currency + { + get + { + return Match( + newFloatingUnit: (x) => x.Currency, + newFloatingTiered: (x) => x.Currency, + newFloatingBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newFloatingPackage: (x) => x.Currency, + newFloatingMatrix: (x) => x.Currency, + newFloatingThresholdTotalAmount: (x) => x.Currency, + newFloatingTieredPackage: (x) => x.Currency, + newFloatingTieredWithMinimum: (x) => x.Currency, + newFloatingGroupedTiered: (x) => x.Currency, + newFloatingTieredPackageWithMinimum: (x) => x.Currency, + newFloatingPackageWithAllocation: (x) => x.Currency, + newFloatingUnitWithPercent: (x) => x.Currency, + newFloatingMatrixWithAllocation: (x) => x.Currency, + newFloatingTieredWithProration: (x) => x.Currency, + newFloatingUnitWithProration: (x) => x.Currency, + newFloatingGroupedAllocation: (x) => x.Currency, + newFloatingBulkWithProration: (x) => x.Currency, + newFloatingGroupedWithProratedMinimum: (x) => x.Currency, + newFloatingGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newFloatingMatrixWithDisplayName: (x) => x.Currency, + newFloatingGroupedTieredPackage: (x) => x.Currency, + newFloatingMaxGroupTieredPackage: (x) => x.Currency, + newFloatingScalableMatrixWithUnitPricing: (x) => x.Currency, + newFloatingScalableMatrixWithTieredPricing: (x) => x.Currency, + newFloatingCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newFloatingMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public string ItemID + { + get + { + return Match( + newFloatingUnit: (x) => x.ItemID, + newFloatingTiered: (x) => x.ItemID, + newFloatingBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newFloatingPackage: (x) => x.ItemID, + newFloatingMatrix: (x) => x.ItemID, + newFloatingThresholdTotalAmount: (x) => x.ItemID, + newFloatingTieredPackage: (x) => x.ItemID, + newFloatingTieredWithMinimum: (x) => x.ItemID, + newFloatingGroupedTiered: (x) => x.ItemID, + newFloatingTieredPackageWithMinimum: (x) => x.ItemID, + newFloatingPackageWithAllocation: (x) => x.ItemID, + newFloatingUnitWithPercent: (x) => x.ItemID, + newFloatingMatrixWithAllocation: (x) => x.ItemID, + newFloatingTieredWithProration: (x) => x.ItemID, + newFloatingUnitWithProration: (x) => x.ItemID, + newFloatingGroupedAllocation: (x) => x.ItemID, + newFloatingBulkWithProration: (x) => x.ItemID, + newFloatingGroupedWithProratedMinimum: (x) => x.ItemID, + newFloatingGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newFloatingMatrixWithDisplayName: (x) => x.ItemID, + newFloatingGroupedTieredPackage: (x) => x.ItemID, + newFloatingMaxGroupTieredPackage: (x) => x.ItemID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ItemID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ItemID, + newFloatingCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newFloatingMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newFloatingUnit: (x) => x.Name, + newFloatingTiered: (x) => x.Name, + newFloatingBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newFloatingPackage: (x) => x.Name, + newFloatingMatrix: (x) => x.Name, + newFloatingThresholdTotalAmount: (x) => x.Name, + newFloatingTieredPackage: (x) => x.Name, + newFloatingTieredWithMinimum: (x) => x.Name, + newFloatingGroupedTiered: (x) => x.Name, + newFloatingTieredPackageWithMinimum: (x) => x.Name, + newFloatingPackageWithAllocation: (x) => x.Name, + newFloatingUnitWithPercent: (x) => x.Name, + newFloatingMatrixWithAllocation: (x) => x.Name, + newFloatingTieredWithProration: (x) => x.Name, + newFloatingUnitWithProration: (x) => x.Name, + newFloatingGroupedAllocation: (x) => x.Name, + newFloatingBulkWithProration: (x) => x.Name, + newFloatingGroupedWithProratedMinimum: (x) => x.Name, + newFloatingGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newFloatingMatrixWithDisplayName: (x) => x.Name, + newFloatingGroupedTieredPackage: (x) => x.Name, + newFloatingMaxGroupTieredPackage: (x) => x.Name, + newFloatingScalableMatrixWithUnitPricing: (x) => x.Name, + newFloatingScalableMatrixWithTieredPricing: (x) => x.Name, + newFloatingCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newFloatingMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newFloatingUnit: (x) => x.BillableMetricID, + newFloatingTiered: (x) => x.BillableMetricID, + newFloatingBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newFloatingPackage: (x) => x.BillableMetricID, + newFloatingMatrix: (x) => x.BillableMetricID, + newFloatingThresholdTotalAmount: (x) => x.BillableMetricID, + newFloatingTieredPackage: (x) => x.BillableMetricID, + newFloatingTieredWithMinimum: (x) => x.BillableMetricID, + newFloatingGroupedTiered: (x) => x.BillableMetricID, + newFloatingTieredPackageWithMinimum: (x) => x.BillableMetricID, + newFloatingPackageWithAllocation: (x) => x.BillableMetricID, + newFloatingUnitWithPercent: (x) => x.BillableMetricID, + newFloatingMatrixWithAllocation: (x) => x.BillableMetricID, + newFloatingTieredWithProration: (x) => x.BillableMetricID, + newFloatingUnitWithProration: (x) => x.BillableMetricID, + newFloatingGroupedAllocation: (x) => x.BillableMetricID, + newFloatingBulkWithProration: (x) => x.BillableMetricID, + newFloatingGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newFloatingGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newFloatingMatrixWithDisplayName: (x) => x.BillableMetricID, + newFloatingGroupedTieredPackage: (x) => x.BillableMetricID, + newFloatingMaxGroupTieredPackage: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newFloatingCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newFloatingMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newFloatingUnit: (x) => x.BilledInAdvance, + newFloatingTiered: (x) => x.BilledInAdvance, + newFloatingBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newFloatingPackage: (x) => x.BilledInAdvance, + newFloatingMatrix: (x) => x.BilledInAdvance, + newFloatingThresholdTotalAmount: (x) => x.BilledInAdvance, + newFloatingTieredPackage: (x) => x.BilledInAdvance, + newFloatingTieredWithMinimum: (x) => x.BilledInAdvance, + newFloatingGroupedTiered: (x) => x.BilledInAdvance, + newFloatingTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newFloatingPackageWithAllocation: (x) => x.BilledInAdvance, + newFloatingUnitWithPercent: (x) => x.BilledInAdvance, + newFloatingMatrixWithAllocation: (x) => x.BilledInAdvance, + newFloatingTieredWithProration: (x) => x.BilledInAdvance, + newFloatingUnitWithProration: (x) => x.BilledInAdvance, + newFloatingGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingBulkWithProration: (x) => x.BilledInAdvance, + newFloatingGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newFloatingGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newFloatingMatrixWithDisplayName: (x) => x.BilledInAdvance, + newFloatingGroupedTieredPackage: (x) => x.BilledInAdvance, + newFloatingMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newFloatingCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newFloatingMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.BillingCycleConfiguration, + newFloatingTiered: (x) => x.BillingCycleConfiguration, + newFloatingBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newFloatingPackage: (x) => x.BillingCycleConfiguration, + newFloatingMatrix: (x) => x.BillingCycleConfiguration, + newFloatingThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTiered: (x) => x.BillingCycleConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newFloatingPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithPercent: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + newFloatingTieredWithProration: (x) => x.BillingCycleConfiguration, + newFloatingUnitWithProration: (x) => x.BillingCycleConfiguration, + newFloatingGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingBulkWithProration: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newFloatingGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newFloatingMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newFloatingUnit: (x) => x.ConversionRate, + newFloatingTiered: (x) => x.ConversionRate, + newFloatingBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newFloatingPackage: (x) => x.ConversionRate, + newFloatingMatrix: (x) => x.ConversionRate, + newFloatingThresholdTotalAmount: (x) => x.ConversionRate, + newFloatingTieredPackage: (x) => x.ConversionRate, + newFloatingTieredWithMinimum: (x) => x.ConversionRate, + newFloatingGroupedTiered: (x) => x.ConversionRate, + newFloatingTieredPackageWithMinimum: (x) => x.ConversionRate, + newFloatingPackageWithAllocation: (x) => x.ConversionRate, + newFloatingUnitWithPercent: (x) => x.ConversionRate, + newFloatingMatrixWithAllocation: (x) => x.ConversionRate, + newFloatingTieredWithProration: (x) => x.ConversionRate, + newFloatingUnitWithProration: (x) => x.ConversionRate, + newFloatingGroupedAllocation: (x) => x.ConversionRate, + newFloatingBulkWithProration: (x) => x.ConversionRate, + newFloatingGroupedWithProratedMinimum: (x) => x.ConversionRate, + newFloatingGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newFloatingMatrixWithDisplayName: (x) => x.ConversionRate, + newFloatingGroupedTieredPackage: (x) => x.ConversionRate, + newFloatingMaxGroupTieredPackage: (x) => x.ConversionRate, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newFloatingCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newFloatingMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.DimensionalPriceConfiguration, + newFloatingTiered: (x) => x.DimensionalPriceConfiguration, + newFloatingBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newFloatingPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrix: (x) => x.DimensionalPriceConfiguration, + newFloatingThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingTieredWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newFloatingGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.DimensionalPriceConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.DimensionalPriceConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newFloatingMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newFloatingUnit: (x) => x.ExternalPriceID, + newFloatingTiered: (x) => x.ExternalPriceID, + newFloatingBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newFloatingPackage: (x) => x.ExternalPriceID, + newFloatingMatrix: (x) => x.ExternalPriceID, + newFloatingThresholdTotalAmount: (x) => x.ExternalPriceID, + newFloatingTieredPackage: (x) => x.ExternalPriceID, + newFloatingTieredWithMinimum: (x) => x.ExternalPriceID, + newFloatingGroupedTiered: (x) => x.ExternalPriceID, + newFloatingTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newFloatingPackageWithAllocation: (x) => x.ExternalPriceID, + newFloatingUnitWithPercent: (x) => x.ExternalPriceID, + newFloatingMatrixWithAllocation: (x) => x.ExternalPriceID, + newFloatingTieredWithProration: (x) => x.ExternalPriceID, + newFloatingUnitWithProration: (x) => x.ExternalPriceID, + newFloatingGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingBulkWithProration: (x) => x.ExternalPriceID, + newFloatingGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newFloatingGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newFloatingMatrixWithDisplayName: (x) => x.ExternalPriceID, + newFloatingGroupedTieredPackage: (x) => x.ExternalPriceID, + newFloatingMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newFloatingScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newFloatingCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newFloatingMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newFloatingUnit: (x) => x.FixedPriceQuantity, + newFloatingTiered: (x) => x.FixedPriceQuantity, + newFloatingBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newFloatingPackage: (x) => x.FixedPriceQuantity, + newFloatingMatrix: (x) => x.FixedPriceQuantity, + newFloatingThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newFloatingTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingTieredWithMinimum: (x) => x.FixedPriceQuantity, + newFloatingGroupedTiered: (x) => x.FixedPriceQuantity, + newFloatingTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newFloatingPackageWithAllocation: (x) => x.FixedPriceQuantity, + newFloatingUnitWithPercent: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithAllocation: (x) => x.FixedPriceQuantity, + newFloatingTieredWithProration: (x) => x.FixedPriceQuantity, + newFloatingUnitWithProration: (x) => x.FixedPriceQuantity, + newFloatingGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingBulkWithProration: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newFloatingGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newFloatingMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newFloatingGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newFloatingScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newFloatingCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newFloatingMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newFloatingUnit: (x) => x.InvoiceGroupingKey, + newFloatingTiered: (x) => x.InvoiceGroupingKey, + newFloatingBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newFloatingPackage: (x) => x.InvoiceGroupingKey, + newFloatingMatrix: (x) => x.InvoiceGroupingKey, + newFloatingThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTiered: (x) => x.InvoiceGroupingKey, + newFloatingTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newFloatingPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithPercent: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + newFloatingTieredWithProration: (x) => x.InvoiceGroupingKey, + newFloatingUnitWithProration: (x) => x.InvoiceGroupingKey, + newFloatingGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingBulkWithProration: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newFloatingGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newFloatingMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newFloatingGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newFloatingScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newFloatingCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newFloatingMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newFloatingUnit: (x) => x.InvoicingCycleConfiguration, + newFloatingTiered: (x) => x.InvoicingCycleConfiguration, + newFloatingBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newFloatingPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrix: (x) => x.InvoicingCycleConfiguration, + newFloatingThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingTieredWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newFloatingMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newFloatingGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newFloatingScalableMatrixWithTieredPricing: (x) => x.InvoicingCycleConfiguration, + newFloatingCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newFloatingMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public PriceModel(NewFloatingUnitPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(PriceModelBulkWithFilters value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingMatrixPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingThresholdTotalAmountPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingTieredWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingGroupedTieredPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingTieredPackageWithMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingPackageWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingUnitWithPercentPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingMatrixWithAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingTieredWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingUnitWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingGroupedAllocationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingBulkWithProrationPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingGroupedWithProratedMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingGroupedWithMeteredMinimumPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(PriceModelGroupedWithMinMaxThresholds value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingMatrixWithDisplayNamePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingGroupedTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingMaxGroupTieredPackagePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel( + NewFloatingScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModel( + NewFloatingScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingCumulativeGroupedBulkPrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(PriceModelCumulativeGroupedAllocation value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(NewFloatingMinimumCompositePrice value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(PriceModelPercent value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(PriceModelEventOutput value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public PriceModel(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnit(out var value)) { + /// // `value` is of type `NewFloatingUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnit([NotNullWhen(true)] out NewFloatingUnitPrice? value) + { + value = this.Value as NewFloatingUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTiered(out var value)) { + /// // `value` is of type `NewFloatingTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTiered([NotNullWhen(true)] out NewFloatingTieredPrice? value) + { + value = this.Value as NewFloatingTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulk(out var value)) { + /// // `value` is of type `NewFloatingBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulk([NotNullWhen(true)] out NewFloatingBulkPrice? value) + { + value = this.Value as NewFloatingBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `PriceModelBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters([NotNullWhen(true)] out PriceModelBulkWithFilters? value) + { + value = this.Value as PriceModelBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackage(out var value)) { + /// // `value` is of type `NewFloatingPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackage([NotNullWhen(true)] out NewFloatingPackagePrice? value) + { + value = this.Value as NewFloatingPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrix(out var value)) { + /// // `value` is of type `NewFloatingMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrix([NotNullWhen(true)] out NewFloatingMatrixPrice? value) + { + value = this.Value as NewFloatingMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewFloatingThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingThresholdTotalAmount( + [NotNullWhen(true)] out NewFloatingThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewFloatingThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackage( + [NotNullWhen(true)] out NewFloatingTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithMinimum(out var value)) { + /// // `value` is of type `NewFloatingTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithMinimum( + [NotNullWhen(true)] out NewFloatingTieredWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTiered(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTiered( + [NotNullWhen(true)] out NewFloatingGroupedTieredPrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewFloatingTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredPackageWithMinimum( + [NotNullWhen(true)] out NewFloatingTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewFloatingTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingPackageWithAllocation(out var value)) { + /// // `value` is of type `NewFloatingPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingPackageWithAllocation( + [NotNullWhen(true)] out NewFloatingPackageWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithPercent(out var value)) { + /// // `value` is of type `NewFloatingUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithPercent( + [NotNullWhen(true)] out NewFloatingUnitWithPercentPrice? value + ) + { + value = this.Value as NewFloatingUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithAllocation( + [NotNullWhen(true)] out NewFloatingMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewFloatingMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingTieredWithProration(out var value)) { + /// // `value` is of type `NewFloatingTieredWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingTieredWithProration( + [NotNullWhen(true)] out NewFloatingTieredWithProrationPrice? value + ) + { + value = this.Value as NewFloatingTieredWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingUnitWithProration(out var value)) { + /// // `value` is of type `NewFloatingUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingUnitWithProration( + [NotNullWhen(true)] out NewFloatingUnitWithProrationPrice? value + ) + { + value = this.Value as NewFloatingUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedAllocation(out var value)) { + /// // `value` is of type `NewFloatingGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedAllocation( + [NotNullWhen(true)] out NewFloatingGroupedAllocationPrice? value + ) + { + value = this.Value as NewFloatingGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingBulkWithProration(out var value)) { + /// // `value` is of type `NewFloatingBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingBulkWithProration( + [NotNullWhen(true)] out NewFloatingBulkWithProrationPrice? value + ) + { + value = this.Value as NewFloatingBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewFloatingGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewFloatingGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewFloatingGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewFloatingGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `PriceModelGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] out PriceModelGroupedWithMinMaxThresholds? value + ) + { + value = this.Value as PriceModelGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewFloatingMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMatrixWithDisplayName( + [NotNullWhen(true)] out NewFloatingMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewFloatingMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingGroupedTieredPackage( + [NotNullWhen(true)] out NewFloatingGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewFloatingMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMaxGroupTieredPackage( + [NotNullWhen(true)] out NewFloatingMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewFloatingMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewFloatingScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewFloatingScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewFloatingScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewFloatingCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingCumulativeGroupedBulk( + [NotNullWhen(true)] out NewFloatingCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewFloatingCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `PriceModelCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] out PriceModelCumulativeGroupedAllocation? value + ) + { + value = this.Value as PriceModelCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewFloatingMinimumComposite(out var value)) { + /// // `value` is of type `NewFloatingMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewFloatingMinimumComposite( + [NotNullWhen(true)] out NewFloatingMinimumCompositePrice? value + ) + { + value = this.Value as NewFloatingMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `PriceModelPercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent([NotNullWhen(true)] out PriceModelPercent? value) + { + value = this.Value as PriceModelPercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `PriceModelEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput([NotNullWhen(true)] out PriceModelEventOutput? value) + { + value = this.Value as PriceModelEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (PriceModelBulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (PriceModelGroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (PriceModelCumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (PriceModelPercent value) => {...}, + /// (PriceModelEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newFloatingUnit, + System::Action newFloatingTiered, + System::Action newFloatingBulk, + System::Action bulkWithFilters, + System::Action newFloatingPackage, + System::Action newFloatingMatrix, + System::Action newFloatingThresholdTotalAmount, + System::Action newFloatingTieredPackage, + System::Action newFloatingTieredWithMinimum, + System::Action newFloatingGroupedTiered, + System::Action newFloatingTieredPackageWithMinimum, + System::Action newFloatingPackageWithAllocation, + System::Action newFloatingUnitWithPercent, + System::Action newFloatingMatrixWithAllocation, + System::Action newFloatingTieredWithProration, + System::Action newFloatingUnitWithProration, + System::Action newFloatingGroupedAllocation, + System::Action newFloatingBulkWithProration, + System::Action newFloatingGroupedWithProratedMinimum, + System::Action newFloatingGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newFloatingMatrixWithDisplayName, + System::Action newFloatingGroupedTieredPackage, + System::Action newFloatingMaxGroupTieredPackage, + System::Action newFloatingScalableMatrixWithUnitPricing, + System::Action newFloatingScalableMatrixWithTieredPricing, + System::Action newFloatingCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newFloatingMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewFloatingUnitPrice value: + newFloatingUnit(value); + break; + case NewFloatingTieredPrice value: + newFloatingTiered(value); + break; + case NewFloatingBulkPrice value: + newFloatingBulk(value); + break; + case PriceModelBulkWithFilters value: + bulkWithFilters(value); + break; + case NewFloatingPackagePrice value: + newFloatingPackage(value); + break; + case NewFloatingMatrixPrice value: + newFloatingMatrix(value); + break; + case NewFloatingThresholdTotalAmountPrice value: + newFloatingThresholdTotalAmount(value); + break; + case NewFloatingTieredPackagePrice value: + newFloatingTieredPackage(value); + break; + case NewFloatingTieredWithMinimumPrice value: + newFloatingTieredWithMinimum(value); + break; + case NewFloatingGroupedTieredPrice value: + newFloatingGroupedTiered(value); + break; + case NewFloatingTieredPackageWithMinimumPrice value: + newFloatingTieredPackageWithMinimum(value); + break; + case NewFloatingPackageWithAllocationPrice value: + newFloatingPackageWithAllocation(value); + break; + case NewFloatingUnitWithPercentPrice value: + newFloatingUnitWithPercent(value); + break; + case NewFloatingMatrixWithAllocationPrice value: + newFloatingMatrixWithAllocation(value); + break; + case NewFloatingTieredWithProrationPrice value: + newFloatingTieredWithProration(value); + break; + case NewFloatingUnitWithProrationPrice value: + newFloatingUnitWithProration(value); + break; + case NewFloatingGroupedAllocationPrice value: + newFloatingGroupedAllocation(value); + break; + case NewFloatingBulkWithProrationPrice value: + newFloatingBulkWithProration(value); + break; + case NewFloatingGroupedWithProratedMinimumPrice value: + newFloatingGroupedWithProratedMinimum(value); + break; + case NewFloatingGroupedWithMeteredMinimumPrice value: + newFloatingGroupedWithMeteredMinimum(value); + break; + case PriceModelGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewFloatingMatrixWithDisplayNamePrice value: + newFloatingMatrixWithDisplayName(value); + break; + case NewFloatingGroupedTieredPackagePrice value: + newFloatingGroupedTieredPackage(value); + break; + case NewFloatingMaxGroupTieredPackagePrice value: + newFloatingMaxGroupTieredPackage(value); + break; + case NewFloatingScalableMatrixWithUnitPricingPrice value: + newFloatingScalableMatrixWithUnitPricing(value); + break; + case NewFloatingScalableMatrixWithTieredPricingPrice value: + newFloatingScalableMatrixWithTieredPricing(value); + break; + case NewFloatingCumulativeGroupedBulkPrice value: + newFloatingCumulativeGroupedBulk(value); + break; + case PriceModelCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewFloatingMinimumCompositePrice value: + newFloatingMinimumComposite(value); + break; + case PriceModelPercent value: + percent(value); + break; + case PriceModelEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of PriceModel"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewFloatingUnitPrice value) => {...}, + /// (NewFloatingTieredPrice value) => {...}, + /// (NewFloatingBulkPrice value) => {...}, + /// (PriceModelBulkWithFilters value) => {...}, + /// (NewFloatingPackagePrice value) => {...}, + /// (NewFloatingMatrixPrice value) => {...}, + /// (NewFloatingThresholdTotalAmountPrice value) => {...}, + /// (NewFloatingTieredPackagePrice value) => {...}, + /// (NewFloatingTieredWithMinimumPrice value) => {...}, + /// (NewFloatingGroupedTieredPrice value) => {...}, + /// (NewFloatingTieredPackageWithMinimumPrice value) => {...}, + /// (NewFloatingPackageWithAllocationPrice value) => {...}, + /// (NewFloatingUnitWithPercentPrice value) => {...}, + /// (NewFloatingMatrixWithAllocationPrice value) => {...}, + /// (NewFloatingTieredWithProrationPrice value) => {...}, + /// (NewFloatingUnitWithProrationPrice value) => {...}, + /// (NewFloatingGroupedAllocationPrice value) => {...}, + /// (NewFloatingBulkWithProrationPrice value) => {...}, + /// (NewFloatingGroupedWithProratedMinimumPrice value) => {...}, + /// (NewFloatingGroupedWithMeteredMinimumPrice value) => {...}, + /// (PriceModelGroupedWithMinMaxThresholds value) => {...}, + /// (NewFloatingMatrixWithDisplayNamePrice value) => {...}, + /// (NewFloatingGroupedTieredPackagePrice value) => {...}, + /// (NewFloatingMaxGroupTieredPackagePrice value) => {...}, + /// (NewFloatingScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewFloatingScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewFloatingCumulativeGroupedBulkPrice value) => {...}, + /// (PriceModelCumulativeGroupedAllocation value) => {...}, + /// (NewFloatingMinimumCompositePrice value) => {...}, + /// (PriceModelPercent value) => {...}, + /// (PriceModelEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newFloatingUnit, + System::Func newFloatingTiered, + System::Func newFloatingBulk, + System::Func bulkWithFilters, + System::Func newFloatingPackage, + System::Func newFloatingMatrix, + System::Func newFloatingThresholdTotalAmount, + System::Func newFloatingTieredPackage, + System::Func newFloatingTieredWithMinimum, + System::Func newFloatingGroupedTiered, + System::Func< + NewFloatingTieredPackageWithMinimumPrice, + T + > newFloatingTieredPackageWithMinimum, + System::Func newFloatingPackageWithAllocation, + System::Func newFloatingUnitWithPercent, + System::Func newFloatingMatrixWithAllocation, + System::Func newFloatingTieredWithProration, + System::Func newFloatingUnitWithProration, + System::Func newFloatingGroupedAllocation, + System::Func newFloatingBulkWithProration, + System::Func< + NewFloatingGroupedWithProratedMinimumPrice, + T + > newFloatingGroupedWithProratedMinimum, + System::Func< + NewFloatingGroupedWithMeteredMinimumPrice, + T + > newFloatingGroupedWithMeteredMinimum, + System::Func groupedWithMinMaxThresholds, + System::Func newFloatingMatrixWithDisplayName, + System::Func newFloatingGroupedTieredPackage, + System::Func newFloatingMaxGroupTieredPackage, + System::Func< + NewFloatingScalableMatrixWithUnitPricingPrice, + T + > newFloatingScalableMatrixWithUnitPricing, + System::Func< + NewFloatingScalableMatrixWithTieredPricingPrice, + T + > newFloatingScalableMatrixWithTieredPricing, + System::Func newFloatingCumulativeGroupedBulk, + System::Func cumulativeGroupedAllocation, + System::Func newFloatingMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewFloatingUnitPrice value => newFloatingUnit(value), + NewFloatingTieredPrice value => newFloatingTiered(value), + NewFloatingBulkPrice value => newFloatingBulk(value), + PriceModelBulkWithFilters value => bulkWithFilters(value), + NewFloatingPackagePrice value => newFloatingPackage(value), + NewFloatingMatrixPrice value => newFloatingMatrix(value), + NewFloatingThresholdTotalAmountPrice value => newFloatingThresholdTotalAmount(value), + NewFloatingTieredPackagePrice value => newFloatingTieredPackage(value), + NewFloatingTieredWithMinimumPrice value => newFloatingTieredWithMinimum(value), + NewFloatingGroupedTieredPrice value => newFloatingGroupedTiered(value), + NewFloatingTieredPackageWithMinimumPrice value => newFloatingTieredPackageWithMinimum( + value + ), + NewFloatingPackageWithAllocationPrice value => newFloatingPackageWithAllocation(value), + NewFloatingUnitWithPercentPrice value => newFloatingUnitWithPercent(value), + NewFloatingMatrixWithAllocationPrice value => newFloatingMatrixWithAllocation(value), + NewFloatingTieredWithProrationPrice value => newFloatingTieredWithProration(value), + NewFloatingUnitWithProrationPrice value => newFloatingUnitWithProration(value), + NewFloatingGroupedAllocationPrice value => newFloatingGroupedAllocation(value), + NewFloatingBulkWithProrationPrice value => newFloatingBulkWithProration(value), + NewFloatingGroupedWithProratedMinimumPrice value => + newFloatingGroupedWithProratedMinimum(value), + NewFloatingGroupedWithMeteredMinimumPrice value => newFloatingGroupedWithMeteredMinimum( + value + ), + PriceModelGroupedWithMinMaxThresholds value => groupedWithMinMaxThresholds(value), + NewFloatingMatrixWithDisplayNamePrice value => newFloatingMatrixWithDisplayName(value), + NewFloatingGroupedTieredPackagePrice value => newFloatingGroupedTieredPackage(value), + NewFloatingMaxGroupTieredPackagePrice value => newFloatingMaxGroupTieredPackage(value), + NewFloatingScalableMatrixWithUnitPricingPrice value => + newFloatingScalableMatrixWithUnitPricing(value), + NewFloatingScalableMatrixWithTieredPricingPrice value => + newFloatingScalableMatrixWithTieredPricing(value), + NewFloatingCumulativeGroupedBulkPrice value => newFloatingCumulativeGroupedBulk(value), + PriceModelCumulativeGroupedAllocation value => cumulativeGroupedAllocation(value), + NewFloatingMinimumCompositePrice value => newFloatingMinimumComposite(value), + PriceModelPercent value => percent(value), + PriceModelEventOutput value => eventOutput(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of PriceModel"), + }; + } + + public static implicit operator PriceModel(NewFloatingUnitPrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingTieredPrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingBulkPrice value) => new(value); + + public static implicit operator PriceModel(PriceModelBulkWithFilters value) => new(value); + + public static implicit operator PriceModel(NewFloatingPackagePrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingMatrixPrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingThresholdTotalAmountPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingTieredPackagePrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingTieredWithMinimumPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingGroupedTieredPrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingTieredPackageWithMinimumPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingPackageWithAllocationPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingUnitWithPercentPrice value) => new(value); + + public static implicit operator PriceModel(NewFloatingMatrixWithAllocationPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingTieredWithProrationPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingUnitWithProrationPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingGroupedAllocationPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingBulkWithProrationPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingGroupedWithProratedMinimumPrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingGroupedWithMeteredMinimumPrice value) => + new(value); + + public static implicit operator PriceModel(PriceModelGroupedWithMinMaxThresholds value) => + new(value); + + public static implicit operator PriceModel(NewFloatingMatrixWithDisplayNamePrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingGroupedTieredPackagePrice value) => + new(value); + + public static implicit operator PriceModel(NewFloatingMaxGroupTieredPackagePrice value) => + new(value); + + public static implicit operator PriceModel( + NewFloatingScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator PriceModel( + NewFloatingScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator PriceModel(NewFloatingCumulativeGroupedBulkPrice value) => + new(value); + + public static implicit operator PriceModel(PriceModelCumulativeGroupedAllocation value) => + new(value); + + public static implicit operator PriceModel(NewFloatingMinimumCompositePrice value) => + new(value); + + public static implicit operator PriceModel(PriceModelPercent value) => new(value); + + public static implicit operator PriceModel(PriceModelEventOutput value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of PriceModel"); + } + this.Switch( + (newFloatingUnit) => newFloatingUnit.Validate(), + (newFloatingTiered) => newFloatingTiered.Validate(), + (newFloatingBulk) => newFloatingBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newFloatingPackage) => newFloatingPackage.Validate(), + (newFloatingMatrix) => newFloatingMatrix.Validate(), + (newFloatingThresholdTotalAmount) => newFloatingThresholdTotalAmount.Validate(), + (newFloatingTieredPackage) => newFloatingTieredPackage.Validate(), + (newFloatingTieredWithMinimum) => newFloatingTieredWithMinimum.Validate(), + (newFloatingGroupedTiered) => newFloatingGroupedTiered.Validate(), + (newFloatingTieredPackageWithMinimum) => newFloatingTieredPackageWithMinimum.Validate(), + (newFloatingPackageWithAllocation) => newFloatingPackageWithAllocation.Validate(), + (newFloatingUnitWithPercent) => newFloatingUnitWithPercent.Validate(), + (newFloatingMatrixWithAllocation) => newFloatingMatrixWithAllocation.Validate(), + (newFloatingTieredWithProration) => newFloatingTieredWithProration.Validate(), + (newFloatingUnitWithProration) => newFloatingUnitWithProration.Validate(), + (newFloatingGroupedAllocation) => newFloatingGroupedAllocation.Validate(), + (newFloatingBulkWithProration) => newFloatingBulkWithProration.Validate(), + (newFloatingGroupedWithProratedMinimum) => + newFloatingGroupedWithProratedMinimum.Validate(), + (newFloatingGroupedWithMeteredMinimum) => + newFloatingGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newFloatingMatrixWithDisplayName) => newFloatingMatrixWithDisplayName.Validate(), + (newFloatingGroupedTieredPackage) => newFloatingGroupedTieredPackage.Validate(), + (newFloatingMaxGroupTieredPackage) => newFloatingMaxGroupTieredPackage.Validate(), + (newFloatingScalableMatrixWithUnitPricing) => + newFloatingScalableMatrixWithUnitPricing.Validate(), + (newFloatingScalableMatrixWithTieredPricing) => + newFloatingScalableMatrixWithTieredPricing.Validate(), + (newFloatingCumulativeGroupedBulk) => newFloatingCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newFloatingMinimumComposite) => newFloatingMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(PriceModel? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceModelConverter : JsonConverter +{ + public override PriceModel? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceModel(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceModel? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class PriceModelBulkWithFilters : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required PriceModelBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceModelBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceModelBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public PriceModelBulkWithFilters(PriceModelBulkWithFilters priceModelBulkWithFilters) + : base(priceModelBulkWithFilters) { } + + public PriceModelBulkWithFilters(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelBulkWithFilters(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelBulkWithFiltersFromRaw : IFromRawJson +{ + /// + public PriceModelBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelBulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelBulkWithFiltersBulkWithFiltersConfig, + PriceModelBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class PriceModelBulkWithFiltersBulkWithFiltersConfig : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public PriceModelBulkWithFiltersBulkWithFiltersConfig() { } + + public PriceModelBulkWithFiltersBulkWithFiltersConfig( + PriceModelBulkWithFiltersBulkWithFiltersConfig priceModelBulkWithFiltersBulkWithFiltersConfig + ) + : base(priceModelBulkWithFiltersBulkWithFiltersConfig) { } + + public PriceModelBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelBulkWithFiltersBulkWithFiltersConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public PriceModelBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelBulkWithFiltersBulkWithFiltersConfigFilter, + PriceModelBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class PriceModelBulkWithFiltersBulkWithFiltersConfigFilter : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public PriceModelBulkWithFiltersBulkWithFiltersConfigFilter() { } + + public PriceModelBulkWithFiltersBulkWithFiltersConfigFilter( + PriceModelBulkWithFiltersBulkWithFiltersConfigFilter priceModelBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base(priceModelBulkWithFiltersBulkWithFiltersConfigFilter) { } + + public PriceModelBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public PriceModelBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked(rawData); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelBulkWithFiltersBulkWithFiltersConfigTier, + PriceModelBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class PriceModelBulkWithFiltersBulkWithFiltersConfigTier : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public PriceModelBulkWithFiltersBulkWithFiltersConfigTier() { } + + public PriceModelBulkWithFiltersBulkWithFiltersConfigTier( + PriceModelBulkWithFiltersBulkWithFiltersConfigTier priceModelBulkWithFiltersBulkWithFiltersConfigTier + ) + : base(priceModelBulkWithFiltersBulkWithFiltersConfigTier) { } + + public PriceModelBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceModelBulkWithFiltersBulkWithFiltersConfigTier(string unitAmount) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class PriceModelBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public PriceModelBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceModelBulkWithFiltersCadenceConverter))] +public enum PriceModelBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceModelBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override PriceModelBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceModelBulkWithFiltersCadence.Annual, + "semi_annual" => PriceModelBulkWithFiltersCadence.SemiAnnual, + "monthly" => PriceModelBulkWithFiltersCadence.Monthly, + "quarterly" => PriceModelBulkWithFiltersCadence.Quarterly, + "one_time" => PriceModelBulkWithFiltersCadence.OneTime, + "custom" => PriceModelBulkWithFiltersCadence.Custom, + _ => (PriceModelBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceModelBulkWithFiltersCadence.Annual => "annual", + PriceModelBulkWithFiltersCadence.SemiAnnual => "semi_annual", + PriceModelBulkWithFiltersCadence.Monthly => "monthly", + PriceModelBulkWithFiltersCadence.Quarterly => "quarterly", + PriceModelBulkWithFiltersCadence.OneTime => "one_time", + PriceModelBulkWithFiltersCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(PriceModelBulkWithFiltersConversionRateConfigConverter))] +public record class PriceModelBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceModelBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelBulkWithFiltersConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator PriceModelBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceModelBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceModelBulkWithFiltersConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceModelBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override PriceModelBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceModelBulkWithFiltersConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceModelGroupedWithMinMaxThresholds, + PriceModelGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class PriceModelGroupedWithMinMaxThresholds : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceModelGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceModelGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public PriceModelGroupedWithMinMaxThresholds( + PriceModelGroupedWithMinMaxThresholds priceModelGroupedWithMinMaxThresholds + ) + : base(priceModelGroupedWithMinMaxThresholds) { } + + public PriceModelGroupedWithMinMaxThresholds(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelGroupedWithMinMaxThresholds(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public PriceModelGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelGroupedWithMinMaxThresholds.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceModelGroupedWithMinMaxThresholdsCadenceConverter))] +public enum PriceModelGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceModelGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override PriceModelGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceModelGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => PriceModelGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => PriceModelGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => PriceModelGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => PriceModelGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => PriceModelGroupedWithMinMaxThresholdsCadence.Custom, + _ => (PriceModelGroupedWithMinMaxThresholdsCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceModelGroupedWithMinMaxThresholdsCadence.Annual => "annual", + PriceModelGroupedWithMinMaxThresholdsCadence.SemiAnnual => "semi_annual", + PriceModelGroupedWithMinMaxThresholdsCadence.Monthly => "monthly", + PriceModelGroupedWithMinMaxThresholdsCadence.Quarterly => "quarterly", + PriceModelGroupedWithMinMaxThresholdsCadence.OneTime => "one_time", + PriceModelGroupedWithMinMaxThresholdsCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() { } + + public PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig priceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base(priceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig) { } + + public PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceModelGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(PriceModelGroupedWithMinMaxThresholdsConversionRateConfigConverter))] +public record class PriceModelGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceModelGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelGroupedWithMinMaxThresholdsConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator PriceModelGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceModelGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceModelGroupedWithMinMaxThresholdsConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceModelGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override PriceModelGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceModelGroupedWithMinMaxThresholdsConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + PriceModelCumulativeGroupedAllocation, + PriceModelCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class PriceModelCumulativeGroupedAllocation : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceModelCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceModelCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public PriceModelCumulativeGroupedAllocation( + PriceModelCumulativeGroupedAllocation priceModelCumulativeGroupedAllocation + ) + : base(priceModelCumulativeGroupedAllocation) { } + + public PriceModelCumulativeGroupedAllocation(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelCumulativeGroupedAllocation(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public PriceModelCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelCumulativeGroupedAllocation.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceModelCumulativeGroupedAllocationCadenceConverter))] +public enum PriceModelCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceModelCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override PriceModelCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceModelCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => PriceModelCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => PriceModelCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => PriceModelCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => PriceModelCumulativeGroupedAllocationCadence.OneTime, + "custom" => PriceModelCumulativeGroupedAllocationCadence.Custom, + _ => (PriceModelCumulativeGroupedAllocationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceModelCumulativeGroupedAllocationCadence.Annual => "annual", + PriceModelCumulativeGroupedAllocationCadence.SemiAnnual => "semi_annual", + PriceModelCumulativeGroupedAllocationCadence.Monthly => "monthly", + PriceModelCumulativeGroupedAllocationCadence.Quarterly => "quarterly", + PriceModelCumulativeGroupedAllocationCadence.OneTime => "one_time", + PriceModelCumulativeGroupedAllocationCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() { } + + public PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig priceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base(priceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig) { } + + public PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + PriceModelCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter(typeof(PriceModelCumulativeGroupedAllocationConversionRateConfigConverter))] +public record class PriceModelCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceModelCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelCumulativeGroupedAllocationConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator PriceModelCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceModelCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceModelCumulativeGroupedAllocationConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceModelCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override PriceModelCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceModelCumulativeGroupedAllocationConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceModelPercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required PriceModelPercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceModelPercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceModelPercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public PriceModelPercent(PriceModelPercent priceModelPercent) + : base(priceModelPercent) { } + + public PriceModelPercent(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelPercent(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelPercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelPercentFromRaw : IFromRawJson +{ + /// + public PriceModelPercent FromRawUnchecked(IReadOnlyDictionary rawData) => + PriceModelPercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceModelPercentCadenceConverter))] +public enum PriceModelPercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceModelPercentCadenceConverter : JsonConverter +{ + public override PriceModelPercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceModelPercentCadence.Annual, + "semi_annual" => PriceModelPercentCadence.SemiAnnual, + "monthly" => PriceModelPercentCadence.Monthly, + "quarterly" => PriceModelPercentCadence.Quarterly, + "one_time" => PriceModelPercentCadence.OneTime, + "custom" => PriceModelPercentCadence.Custom, + _ => (PriceModelPercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelPercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceModelPercentCadence.Annual => "annual", + PriceModelPercentCadence.SemiAnnual => "semi_annual", + PriceModelPercentCadence.Monthly => "monthly", + PriceModelPercentCadence.Quarterly => "quarterly", + PriceModelPercentCadence.OneTime => "one_time", + PriceModelPercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelPercentPercentConfig, + PriceModelPercentPercentConfigFromRaw + >) +)] +public sealed record class PriceModelPercentPercentConfig : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public PriceModelPercentPercentConfig() { } + + public PriceModelPercentPercentConfig( + PriceModelPercentPercentConfig priceModelPercentPercentConfig + ) + : base(priceModelPercentPercentConfig) { } + + public PriceModelPercentPercentConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelPercentPercentConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelPercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceModelPercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class PriceModelPercentPercentConfigFromRaw : IFromRawJson +{ + /// + public PriceModelPercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelPercentPercentConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceModelPercentConversionRateConfigConverter))] +public record class PriceModelPercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceModelPercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelPercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelPercentConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelPercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelPercentConversionRateConfig" + ), + }; + } + + public static implicit operator PriceModelPercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceModelPercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelPercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceModelPercentConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceModelPercentConversionRateConfigConverter + : JsonConverter +{ + public override PriceModelPercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceModelPercentConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelPercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class PriceModelEventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum Cadence + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "cadence" + ); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// An ISO 4217 currency string for which this price is billed in. + /// + public required string Currency + { + get { return JsonModel.GetNotNullClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required PriceModelEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public PriceModelEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.Currency; + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + } + + public PriceModelEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public PriceModelEventOutput(PriceModelEventOutput priceModelEventOutput) + : base(priceModelEventOutput) { } + + public PriceModelEventOutput(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelEventOutput(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class PriceModelEventOutputFromRaw : IFromRawJson +{ + /// + public PriceModelEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(PriceModelEventOutputCadenceConverter))] +public enum PriceModelEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class PriceModelEventOutputCadenceConverter : JsonConverter +{ + public override PriceModelEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => PriceModelEventOutputCadence.Annual, + "semi_annual" => PriceModelEventOutputCadence.SemiAnnual, + "monthly" => PriceModelEventOutputCadence.Monthly, + "quarterly" => PriceModelEventOutputCadence.Quarterly, + "one_time" => PriceModelEventOutputCadence.OneTime, + "custom" => PriceModelEventOutputCadence.Custom, + _ => (PriceModelEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + PriceModelEventOutputCadence.Annual => "annual", + PriceModelEventOutputCadence.SemiAnnual => "semi_annual", + PriceModelEventOutputCadence.Monthly => "monthly", + PriceModelEventOutputCadence.Quarterly => "quarterly", + PriceModelEventOutputCadence.OneTime => "one_time", + PriceModelEventOutputCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + PriceModelEventOutputEventOutputConfig, + PriceModelEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class PriceModelEventOutputEventOutputConfig : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public PriceModelEventOutputEventOutputConfig() { } + + public PriceModelEventOutputEventOutputConfig( + PriceModelEventOutputEventOutputConfig priceModelEventOutputEventOutputConfig + ) + : base(priceModelEventOutputEventOutputConfig) { } + + public PriceModelEventOutputEventOutputConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + PriceModelEventOutputEventOutputConfig(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static PriceModelEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public PriceModelEventOutputEventOutputConfig(string unitRatingKey) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class PriceModelEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public PriceModelEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => PriceModelEventOutputEventOutputConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(PriceModelEventOutputConversionRateConfigConverter))] +public record class PriceModelEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public PriceModelEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public PriceModelEventOutputConversionRateConfig(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator PriceModelEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator PriceModelEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of PriceModelEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals(PriceModelEventOutputConversionRateConfig? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class PriceModelEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override PriceModelEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new PriceModelEventOutputConversionRateConfig(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + PriceModelEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionPriceIntervalsParamsAddAdjustment, + SubscriptionPriceIntervalsParamsAddAdjustmentFromRaw + >) +)] +public sealed record class SubscriptionPriceIntervalsParamsAddAdjustment : JsonModel +{ + /// + /// The start date of the adjustment interval. This is the date that the adjustment + /// will start affecting prices on the subscription. The adjustment will apply + /// to invoice dates that overlap with this `start_date`. This `start_date` is + /// treated as inclusive for in-advance prices, and exclusive for in-arrears prices. + /// + public required SubscriptionPriceIntervalsParamsAddAdjustmentStartDate StartDate + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "start_date" + ); + } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + /// The definition of a new adjustment to create and add to the subscription. + /// + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment? Adjustment + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "adjustment" + ); + } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The ID of the adjustment to add to the subscription. Adjustment IDs can be + /// re-used from existing subscriptions or plans, but adjustments associated with + /// coupon redemptions cannot be re-used. + /// + public string? AdjustmentID + { + get { return JsonModel.GetNullableClass(this.RawData, "adjustment_id"); } + init { JsonModel.Set(this._rawData, "adjustment_id", value); } + } + + /// + /// The end date of the adjustment interval. This is the date that the adjustment + /// will stop affecting prices on the subscription. The adjustment will apply + /// to invoice dates that overlap with this `end_date`.This `end_date` is treated + /// as exclusive for in-advance prices, and inclusive for in-arrears prices. + /// + public SubscriptionPriceIntervalsParamsAddAdjustmentEndDate? EndDate + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "end_date" + ); + } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + public override void Validate() + { + this.StartDate.Validate(); + this.Adjustment?.Validate(); + _ = this.AdjustmentID; + this.EndDate?.Validate(); + } + + public SubscriptionPriceIntervalsParamsAddAdjustment() { } + + public SubscriptionPriceIntervalsParamsAddAdjustment( + SubscriptionPriceIntervalsParamsAddAdjustment subscriptionPriceIntervalsParamsAddAdjustment + ) + : base(subscriptionPriceIntervalsParamsAddAdjustment) { } + + public SubscriptionPriceIntervalsParamsAddAdjustment( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionPriceIntervalsParamsAddAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionPriceIntervalsParamsAddAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionPriceIntervalsParamsAddAdjustment( + SubscriptionPriceIntervalsParamsAddAdjustmentStartDate startDate + ) + : this() + { + this.StartDate = startDate; + } +} + +class SubscriptionPriceIntervalsParamsAddAdjustmentFromRaw + : IFromRawJson +{ + /// + public SubscriptionPriceIntervalsParamsAddAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionPriceIntervalsParamsAddAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The start date of the adjustment interval. This is the date that the adjustment +/// will start affecting prices on the subscription. The adjustment will apply to +/// invoice dates that overlap with this `start_date`. This `start_date` is treated +/// as inclusive for in-advance prices, and exclusive for in-arrears prices. +/// +[JsonConverter(typeof(SubscriptionPriceIntervalsParamsAddAdjustmentStartDateConverter))] +public record class SubscriptionPriceIntervalsParamsAddAdjustmentStartDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentStartDate( + System::DateTimeOffset value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentStartDate( + ApiEnum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentStartDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentStartDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentStartDate" + ), + }; + } + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentStartDate( + System::DateTimeOffset value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentStartDate( + ApiEnum value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentStartDate( + BillingCycleRelativeDate value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentStartDate" + ); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(SubscriptionPriceIntervalsParamsAddAdjustmentStartDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionPriceIntervalsParamsAddAdjustmentStartDateConverter + : JsonConverter +{ + public override SubscriptionPriceIntervalsParamsAddAdjustmentStartDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionPriceIntervalsParamsAddAdjustmentStartDate value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// The definition of a new adjustment to create and add to the subscription. +/// +[JsonConverter(typeof(SubscriptionPriceIntervalsParamsAddAdjustmentAdjustmentConverter))] +public record class SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewPercentageDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewUsageDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewAmountDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewMinimum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewMaximum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment" + ), + }; + } + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewUsageDiscount value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewAmountDiscount value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewMinimum value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment( + NewMaximum value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionPriceIntervalsParamsAddAdjustmentAdjustmentConverter + : JsonConverter +{ + public override SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionPriceIntervalsParamsAddAdjustmentAdjustment? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +/// +/// The end date of the adjustment interval. This is the date that the adjustment +/// will stop affecting prices on the subscription. The adjustment will apply to +/// invoice dates that overlap with this `end_date`.This `end_date` is treated as +/// exclusive for in-advance prices, and inclusive for in-arrears prices. +/// +[JsonConverter(typeof(SubscriptionPriceIntervalsParamsAddAdjustmentEndDateConverter))] +public record class SubscriptionPriceIntervalsParamsAddAdjustmentEndDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentEndDate( + System::DateTimeOffset value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentEndDate( + ApiEnum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionPriceIntervalsParamsAddAdjustmentEndDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentEndDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentEndDate" + ), + }; + } + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentEndDate( + System::DateTimeOffset value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentEndDate( + ApiEnum value + ) => new(value); + + public static implicit operator SubscriptionPriceIntervalsParamsAddAdjustmentEndDate( + BillingCycleRelativeDate value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionPriceIntervalsParamsAddAdjustmentEndDate" + ); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(SubscriptionPriceIntervalsParamsAddAdjustmentEndDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionPriceIntervalsParamsAddAdjustmentEndDateConverter + : JsonConverter +{ + public override SubscriptionPriceIntervalsParamsAddAdjustmentEndDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionPriceIntervalsParamsAddAdjustmentEndDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Edit : JsonModel +{ + /// + /// The id of the price interval to edit. + /// + public required string PriceIntervalID + { + get { return JsonModel.GetNotNullClass(this.RawData, "price_interval_id"); } + init { JsonModel.Set(this._rawData, "price_interval_id", value); } + } + + /// + /// The updated billing cycle day for this price interval. If not specified, + /// the billing cycle day will not be updated. Note that overlapping price intervals + /// must have the same billing cycle day. + /// + public long? BillingCycleDay + { + get { return JsonModel.GetNullableStruct(this.RawData, "billing_cycle_day"); } + init { JsonModel.Set(this._rawData, "billing_cycle_day", value); } + } + + /// + /// If true, an in-arrears price interval ending mid-cycle will defer billing + /// the final line item until the next scheduled invoice. If false, it will be + /// billed on its end date. + /// + public bool? CanDeferBilling + { + get { return JsonModel.GetNullableStruct(this.RawData, "can_defer_billing"); } + init { JsonModel.Set(this._rawData, "can_defer_billing", value); } + } + + /// + /// The updated end date of this price interval. If not specified, the end date + /// will not be updated. + /// + public EditEndDate? EndDate + { + get { return JsonModel.GetNullableClass(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// An additional filter to apply to usage queries. This filter must be expressed + /// as a boolean [computed property](/extensibility/advanced-metrics#computed-properties). + /// If null, usage queries will not include any additional filter. + /// + public string? Filter + { + get { return JsonModel.GetNullableClass(this.RawData, "filter"); } + init { JsonModel.Set(this._rawData, "filter", value); } + } + + /// + /// A list of fixed fee quantity transitions to use for this price interval. Note + /// that this list will overwrite all existing fixed fee quantity transitions + /// on the price interval. + /// + public IReadOnlyList? FixedFeeQuantityTransitions + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "fixed_fee_quantity_transitions" + ); + } + init { JsonModel.Set(this._rawData, "fixed_fee_quantity_transitions", value); } + } + + /// + /// The updated start date of this price interval. If not specified, the start + /// date will not be updated. + /// + public EditStartDate? StartDate + { + get { return JsonModel.GetNullableClass(this.RawData, "start_date"); } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "start_date", value); + } + } + + /// + /// A list of customer IDs whose usage events will be aggregated and billed under + /// this subscription. By default, a subscription only considers usage events + /// associated with its attached customer's customer_id. When usage_customer_ids + /// is provided, the subscription includes usage events from the specified customers + /// only. Provided usage_customer_ids must be either the customer for this subscription + /// itself, or any of that customer's children. + /// + public IReadOnlyList? UsageCustomerIDs + { + get { return JsonModel.GetNullableClass>(this.RawData, "usage_customer_ids"); } + init { JsonModel.Set(this._rawData, "usage_customer_ids", value); } + } + + /// + public override void Validate() + { + _ = this.PriceIntervalID; + _ = this.BillingCycleDay; + _ = this.CanDeferBilling; + this.EndDate?.Validate(); + _ = this.Filter; + foreach (var item in this.FixedFeeQuantityTransitions ?? []) + { + item.Validate(); + } + this.StartDate?.Validate(); + _ = this.UsageCustomerIDs; + } + + public Edit() { } + + public Edit(Edit edit) + : base(edit) { } + + public Edit(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Edit(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Edit FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public Edit(string priceIntervalID) + : this() + { + this.PriceIntervalID = priceIntervalID; + } +} + +class EditFromRaw : IFromRawJson +{ + /// + public Edit FromRawUnchecked(IReadOnlyDictionary rawData) => + Edit.FromRawUnchecked(rawData); +} + +/// +/// The updated end date of this price interval. If not specified, the end date will +/// not be updated. +/// +[JsonConverter(typeof(EditEndDateConverter))] +public record class EditEndDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EditEndDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EditEndDate(ApiEnum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EditEndDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of EditEndDate"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException("Data did not match any variant of EditEndDate"), + }; + } + + public static implicit operator EditEndDate(System::DateTimeOffset value) => new(value); + + public static implicit operator EditEndDate(ApiEnum value) => + new(value); + + public static implicit operator EditEndDate(BillingCycleRelativeDate value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of EditEndDate"); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(EditEndDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EditEndDateConverter : JsonConverter +{ + public override EditEndDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + EditEndDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + EditFixedFeeQuantityTransition, + EditFixedFeeQuantityTransitionFromRaw + >) +)] +public sealed record class EditFixedFeeQuantityTransition : JsonModel +{ + /// + /// The date that the fixed fee quantity transition should take effect. + /// + public required System::DateTimeOffset EffectiveDate + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "effective_date" + ); + } + init { JsonModel.Set(this._rawData, "effective_date", value); } + } + + /// + /// The quantity of the fixed fee quantity transition. + /// + public required long Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + /// + public override void Validate() + { + _ = this.EffectiveDate; + _ = this.Quantity; + } + + public EditFixedFeeQuantityTransition() { } + + public EditFixedFeeQuantityTransition( + EditFixedFeeQuantityTransition editFixedFeeQuantityTransition + ) + : base(editFixedFeeQuantityTransition) { } + + public EditFixedFeeQuantityTransition(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EditFixedFeeQuantityTransition(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static EditFixedFeeQuantityTransition FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class EditFixedFeeQuantityTransitionFromRaw : IFromRawJson +{ + /// + public EditFixedFeeQuantityTransition FromRawUnchecked( + IReadOnlyDictionary rawData + ) => EditFixedFeeQuantityTransition.FromRawUnchecked(rawData); +} + +/// +/// The updated start date of this price interval. If not specified, the start date +/// will not be updated. +/// +[JsonConverter(typeof(EditStartDateConverter))] +public record class EditStartDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EditStartDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EditStartDate( + ApiEnum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EditStartDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EditStartDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EditStartDate" + ), + }; + } + + public static implicit operator EditStartDate(System::DateTimeOffset value) => new(value); + + public static implicit operator EditStartDate( + ApiEnum value + ) => new(value); + + public static implicit operator EditStartDate(BillingCycleRelativeDate value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of EditStartDate"); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(EditStartDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EditStartDateConverter : JsonConverter +{ + public override EditStartDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + EditStartDate value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class EditAdjustment : JsonModel +{ + /// + /// The id of the adjustment interval to edit. + /// + public required string AdjustmentIntervalID + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment_interval_id"); } + init { JsonModel.Set(this._rawData, "adjustment_interval_id", value); } + } + + /// + /// The updated end date of this adjustment interval. If not specified, the end + /// date will not be updated. + /// + public EditAdjustmentEndDate? EndDate + { + get { return JsonModel.GetNullableClass(this.RawData, "end_date"); } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// The updated start date of this adjustment interval. If not specified, the + /// start date will not be updated. + /// + public EditAdjustmentStartDate? StartDate + { + get + { + return JsonModel.GetNullableClass(this.RawData, "start_date"); + } + init + { + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "start_date", value); + } + } + + /// + public override void Validate() + { + _ = this.AdjustmentIntervalID; + this.EndDate?.Validate(); + this.StartDate?.Validate(); + } + + public EditAdjustment() { } + + public EditAdjustment(EditAdjustment editAdjustment) + : base(editAdjustment) { } + + public EditAdjustment(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + EditAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static EditAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public EditAdjustment(string adjustmentIntervalID) + : this() + { + this.AdjustmentIntervalID = adjustmentIntervalID; + } +} + +class EditAdjustmentFromRaw : IFromRawJson +{ + /// + public EditAdjustment FromRawUnchecked(IReadOnlyDictionary rawData) => + EditAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The updated end date of this adjustment interval. If not specified, the end date +/// will not be updated. +/// +[JsonConverter(typeof(EditAdjustmentEndDateConverter))] +public record class EditAdjustmentEndDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EditAdjustmentEndDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EditAdjustmentEndDate( + ApiEnum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EditAdjustmentEndDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EditAdjustmentEndDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EditAdjustmentEndDate" + ), + }; + } + + public static implicit operator EditAdjustmentEndDate(System::DateTimeOffset value) => + new(value); + + public static implicit operator EditAdjustmentEndDate( + ApiEnum value + ) => new(value); + + public static implicit operator EditAdjustmentEndDate(BillingCycleRelativeDate value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EditAdjustmentEndDate" + ); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(EditAdjustmentEndDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EditAdjustmentEndDateConverter : JsonConverter +{ + public override EditAdjustmentEndDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + EditAdjustmentEndDate? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +/// +/// The updated start date of this adjustment interval. If not specified, the start +/// date will not be updated. +/// +[JsonConverter(typeof(EditAdjustmentStartDateConverter))] +public record class EditAdjustmentStartDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public EditAdjustmentStartDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public EditAdjustmentStartDate( + ApiEnum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public EditAdjustmentStartDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTime(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTime([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBillingCycleRelative(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBillingCycleRelative( + [NotNullWhen(true)] out ApiEnum? value + ) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTime, + System::Action> billingCycleRelative + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTime(value); + break; + case ApiEnum value: + billingCycleRelative(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of EditAdjustmentStartDate" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTime, + System::Func, T> billingCycleRelative + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTime(value), + ApiEnum value => billingCycleRelative(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of EditAdjustmentStartDate" + ), + }; + } + + public static implicit operator EditAdjustmentStartDate(System::DateTimeOffset value) => + new(value); + + public static implicit operator EditAdjustmentStartDate( + ApiEnum value + ) => new(value); + + public static implicit operator EditAdjustmentStartDate(BillingCycleRelativeDate value) => + new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of EditAdjustmentStartDate" + ); + } + this.Switch((_) => { }, (billingCycleRelative) => billingCycleRelative.Validate()); + } + + public virtual bool Equals(EditAdjustmentStartDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class EditAdjustmentStartDateConverter : JsonConverter +{ + public override EditAdjustmentStartDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + EditAdjustmentStartDate value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/Add.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/Add.cs deleted file mode 100644 index 9bfeffe4..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/Add.cs +++ /dev/null @@ -1,269 +0,0 @@ -using AddProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Add : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The start date of the price interval. This is the date that the price will - /// start billing on the subscription. - /// - public required AddProperties::StartDate StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("start_date"); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The definition of a new allocation price to create and add to the subscription. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// A list of discounts to initialize on the price interval. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the price interval. This is the date that the price will stop - /// billing on the subscription. - /// - public AddProperties::EndDate? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external price id of the price to add to the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// An additional filter to apply to usage queries. This filter must be expressed - /// as a boolean [computed property](/extensibility/advanced-metrics#computed-properties). - /// If null, usage queries will not include any additional filter. - /// - public string? Filter - { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A list of fixed fee quantity transitions to initialize on the price interval. - /// - public Generic::List? FixedFeeQuantityTransitions - { - get - { - if ( - !this.Properties.TryGetValue( - "fixed_fee_quantity_transitions", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.Properties["fixed_fee_quantity_transitions"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The maximum amount that will be billed for this price interval for a given billing period. - /// - public double? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The minimum amount that will be billed for this price interval for a given billing period. - /// - public double? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The definition of a new price to create and add to the subscription. - /// - public AddProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the price to add to the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A list of customer IDs whose usage events will be aggregated and billed under - /// this subscription. By default, a subscription only considers usage events associated - /// with its attached customer's customer_id. When usage_customer_ids is provided, - /// the subscription includes usage events from the specified customers only. Provided - /// usage_customer_ids must be either the customer for this subscription itself, - /// or any of that customer's children. - /// - public Generic::List? UsageCustomerIDs - { - get - { - if (!this.Properties.TryGetValue("usage_customer_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.StartDate.Validate(); - this.AllocationPrice?.Validate(); - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - this.EndDate?.Validate(); - _ = this.ExternalPriceID; - _ = this.Filter; - foreach (var item in this.FixedFeeQuantityTransitions ?? []) - { - item.Validate(); - } - _ = this.MaximumAmount; - _ = this.MinimumAmount; - this.Price?.Validate(); - _ = this.PriceID; - foreach (var item in this.UsageCustomerIDs ?? []) - { - _ = item; - } - } - - public Add() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Add(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Add FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustment.cs deleted file mode 100644 index 80d25e11..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustment.cs +++ /dev/null @@ -1,96 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the subscription. - /// - public required AddAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The start date of the adjustment interval. This is the date that the adjustment - /// will start affecting prices on the subscription. The adjustment will apply - /// to invoice dates that overlap with this `start_date`. This `start_date` is treated - /// as inclusive for in-advance prices, and exclusive for in-arrears prices. - /// - public required AddAdjustmentProperties::StartDate StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("start_date"); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the adjustment interval. This is the date that the adjustment - /// will stop affecting prices on the subscription. The adjustment will apply to - /// invoice dates that overlap with this `end_date`.This `end_date` is treated as - /// exclusive for in-advance prices, and inclusive for in-arrears prices. - /// - public AddAdjustmentProperties::EndDate? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Adjustment.Validate(); - this.StartDate.Validate(); - this.EndDate?.Validate(); - } - - public AddAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/Adjustment.cs deleted file mode 100644 index b2bdd274..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index 8b1fe470..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/EndDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/EndDate.cs deleted file mode 100644 index 7c401c1e..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/EndDate.cs +++ /dev/null @@ -1,27 +0,0 @@ -using EndDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties.EndDateVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; - -/// -/// The end date of the adjustment interval. This is the date that the adjustment -/// will stop affecting prices on the subscription. The adjustment will apply to invoice -/// dates that overlap with this `end_date`.This `end_date` is treated as exclusive -/// for in-advance prices, and inclusive for in-arrears prices. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class EndDate -{ - internal EndDate() { } - - public static EndDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static EndDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/EndDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/EndDateVariants/All.cs deleted file mode 100644 index 183de5ad..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/EndDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties.EndDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : AddAdjustmentProperties::EndDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : AddAdjustmentProperties::EndDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/StartDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/StartDate.cs deleted file mode 100644 index cee0595c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/StartDate.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using StartDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties.StartDateVariants; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; - -/// -/// The start date of the adjustment interval. This is the date that the adjustment -/// will start affecting prices on the subscription. The adjustment will apply to -/// invoice dates that overlap with this `start_date`. This `start_date` is treated -/// as inclusive for in-advance prices, and exclusive for in-arrears prices. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class StartDate -{ - internal StartDate() { } - - public static StartDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static StartDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/StartDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/StartDateVariants/All.cs deleted file mode 100644 index 017d629e..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddAdjustmentProperties/StartDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddAdjustmentProperties.StartDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : AddAdjustmentProperties::StartDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : AddAdjustmentProperties::StartDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/Discount.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/Discount.cs deleted file mode 100644 index 011e56fb..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/Discount.cs +++ /dev/null @@ -1,21 +0,0 @@ -using DiscountProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties; -using DiscountVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountVariants; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Discount -{ - internal Discount() { } - - public static DiscountVariants::Amount Create(DiscountProperties::Amount value) => new(value); - - public static DiscountVariants::Percentage Create(DiscountProperties::Percentage value) => - new(value); - - public static DiscountVariants::Usage Create(DiscountProperties::Usage value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Amount.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Amount.cs deleted file mode 100644 index 6e3d705b..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Amount.cs +++ /dev/null @@ -1,68 +0,0 @@ -using AmountProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.AmountProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Amount : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Only available if discount_type is `amount`. - /// - public required double AmountDiscount - { - get - { - if (!this.Properties.TryGetValue("amount_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["amount_discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required AmountProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AmountDiscount; - this.DiscountType.Validate(); - } - - public Amount() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Amount(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Amount FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/AmountProperties/DiscountType.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/AmountProperties/DiscountType.cs deleted file mode 100644 index 4ac283b6..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/AmountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.AmountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Amount = new("amount"); - - readonly string _value = value; - - public enum Value - { - Amount, - } - - public Value Known() => - _value switch - { - "amount" => Value.Amount, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Percentage.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Percentage.cs deleted file mode 100644 index dd773e58..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Percentage.cs +++ /dev/null @@ -1,74 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using PercentageProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.PercentageProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Percentage : Orb::ModelBase, Orb::IFromRaw -{ - public required PercentageProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Only available if discount_type is `percentage`. This is a number between 0 - /// and 1. - /// - public required double PercentageDiscount - { - get - { - if (!this.Properties.TryGetValue("percentage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "percentage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["percentage_discount"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - this.DiscountType.Validate(); - _ = this.PercentageDiscount; - } - - public Percentage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Percentage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Percentage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/PercentageProperties/DiscountType.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/PercentageProperties/DiscountType.cs deleted file mode 100644 index c6777abd..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/PercentageProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.PercentageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Percentage = new("percentage"); - - readonly string _value = value; - - public enum Value - { - Percentage, - } - - public Value Known() => - _value switch - { - "percentage" => Value.Percentage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Usage.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Usage.cs deleted file mode 100644 index 7ebf5aa6..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/Usage.cs +++ /dev/null @@ -1,69 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using UsageProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.UsageProperties; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Usage : Orb::ModelBase, Orb::IFromRaw -{ - public required UsageProperties::DiscountType DiscountType - { - get - { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); - } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Only available if discount_type is `usage`. Number of usage units that this - /// discount is for. - /// - public required double UsageDiscount - { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.DiscountType.Validate(); - _ = this.UsageDiscount; - } - - public Usage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Usage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Usage FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/UsageProperties/DiscountType.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/UsageProperties/DiscountType.cs deleted file mode 100644 index 1f37c4b1..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountProperties/UsageProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties.UsageProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Usage = new("usage"); - - readonly string _value = value; - - public enum Value - { - Usage, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountVariants/All.cs deleted file mode 100644 index c4d514d4..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/DiscountVariants/All.cs +++ /dev/null @@ -1,56 +0,0 @@ -using AddProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; -using DiscountProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.DiscountVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Amount(DiscountProperties::Amount Value) - : AddProperties::Discount, - Orb::IVariant -{ - public static Amount From(DiscountProperties::Amount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class Percentage(DiscountProperties::Percentage Value) - : AddProperties::Discount, - Orb::IVariant -{ - public static Percentage From(DiscountProperties::Percentage value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class Usage(DiscountProperties::Usage Value) - : AddProperties::Discount, - Orb::IVariant -{ - public static Usage From(DiscountProperties::Usage value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/EndDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/EndDate.cs deleted file mode 100644 index b69f5afa..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/EndDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using EndDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.EndDateVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; - -/// -/// The end date of the price interval. This is the date that the price will stop -/// billing on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class EndDate -{ - internal EndDate() { } - - public static EndDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static EndDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/EndDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/EndDateVariants/All.cs deleted file mode 100644 index 465adf4a..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/EndDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using AddProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.EndDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : AddProperties::EndDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : AddProperties::EndDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/FixedFeeQuantityTransition.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/FixedFeeQuantityTransition.cs deleted file mode 100644 index 0b6275ed..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/FixedFeeQuantityTransition.cs +++ /dev/null @@ -1,73 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class FixedFeeQuantityTransition - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The date that the fixed fee quantity transition should take effect. - /// - public required System::DateTime EffectiveDate - { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "effective_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The quantity of the fixed fee quantity transition. - /// - public required long Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.EffectiveDate; - _ = this.Quantity; - } - - public FixedFeeQuantityTransition() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - FixedFeeQuantityTransition(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static FixedFeeQuantityTransition FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/Price.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/Price.cs deleted file mode 100644 index 50ff632c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/Price.cs +++ /dev/null @@ -1,126 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using PriceVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; - -/// -/// The definition of a new price to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewFloatingUnitPrice Create(Models::NewFloatingUnitPrice value) => - new(value); - - public static PriceVariants::NewFloatingPackagePrice Create( - Models::NewFloatingPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixPrice Create( - Models::NewFloatingMatrixPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixWithAllocationPrice Create( - Models::NewFloatingMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPrice Create( - Models::NewFloatingTieredPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredBPSPrice Create( - Models::NewFloatingTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewFloatingBPSPrice Create(Models::NewFloatingBPSPrice value) => - new(value); - - public static PriceVariants::NewFloatingBulkBPSPrice Create( - Models::NewFloatingBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewFloatingBulkPrice Create(Models::NewFloatingBulkPrice value) => - new(value); - - public static PriceVariants::NewFloatingThresholdTotalAmountPrice Create( - Models::NewFloatingThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPackagePrice Create( - Models::NewFloatingTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedTieredPrice Create( - Models::NewFloatingGroupedTieredPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMaxGroupTieredPackagePrice Create( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredWithMinimumPrice Create( - Models::NewFloatingTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingPackageWithAllocationPrice Create( - Models::NewFloatingPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredPackageWithMinimumPrice Create( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingUnitWithPercentPrice Create( - Models::NewFloatingUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewFloatingTieredWithProrationPrice Create( - Models::NewFloatingTieredWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingUnitWithProrationPrice Create( - Models::NewFloatingUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedAllocationPrice Create( - Models::NewFloatingGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedWithProratedMinimumPrice Create( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedWithMeteredMinimumPrice Create( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewFloatingMatrixWithDisplayNamePrice Create( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewFloatingBulkWithProrationPrice Create( - Models::NewFloatingBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewFloatingGroupedTieredPackagePrice Create( - Models::NewFloatingGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewFloatingScalableMatrixWithUnitPricingPrice Create( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewFloatingScalableMatrixWithTieredPricingPrice Create( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewFloatingCumulativeGroupedBulkPrice Create( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/PriceVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/PriceVariants/All.cs deleted file mode 100644 index cca9a00a..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/PriceVariants/All.cs +++ /dev/null @@ -1,685 +0,0 @@ -using AddProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingUnitPrice(Models::NewFloatingUnitPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitPrice From(Models::NewFloatingUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingPackagePrice(Models::NewFloatingPackagePrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingPackagePrice From(Models::NewFloatingPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingMatrixPrice(Models::NewFloatingMatrixPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingMatrixPrice From(Models::NewFloatingMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - >) -)] -public sealed record class NewFloatingMatrixWithAllocationPrice( - Models::NewFloatingMatrixWithAllocationPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingMatrixWithAllocationPrice, - Models::NewFloatingMatrixWithAllocationPrice - > -{ - public static NewFloatingMatrixWithAllocationPrice From( - Models::NewFloatingMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredPrice(Models::NewFloatingTieredPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredPrice From(Models::NewFloatingTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingTieredBPSPrice(Models::NewFloatingTieredBPSPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredBPSPrice From(Models::NewFloatingTieredBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBPSPrice(Models::NewFloatingBPSPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingBPSPrice From(Models::NewFloatingBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkBPSPrice(Models::NewFloatingBulkBPSPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkBPSPrice From(Models::NewFloatingBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewFloatingBulkPrice(Models::NewFloatingBulkPrice Value) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkPrice From(Models::NewFloatingBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - >) -)] -public sealed record class NewFloatingThresholdTotalAmountPrice( - Models::NewFloatingThresholdTotalAmountPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingThresholdTotalAmountPrice, - Models::NewFloatingThresholdTotalAmountPrice - > -{ - public static NewFloatingThresholdTotalAmountPrice From( - Models::NewFloatingThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackagePrice, - Models::NewFloatingTieredPackagePrice - >) -)] -public sealed record class NewFloatingTieredPackagePrice( - Models::NewFloatingTieredPackagePrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredPackagePrice From(Models::NewFloatingTieredPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPrice, - Models::NewFloatingGroupedTieredPrice - >) -)] -public sealed record class NewFloatingGroupedTieredPrice( - Models::NewFloatingGroupedTieredPrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingGroupedTieredPrice From(Models::NewFloatingGroupedTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewFloatingMaxGroupTieredPackagePrice( - Models::NewFloatingMaxGroupTieredPackagePrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingMaxGroupTieredPackagePrice, - Models::NewFloatingMaxGroupTieredPackagePrice - > -{ - public static NewFloatingMaxGroupTieredPackagePrice From( - Models::NewFloatingMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithMinimumPrice, - Models::NewFloatingTieredWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredWithMinimumPrice( - Models::NewFloatingTieredWithMinimumPrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingTieredWithMinimumPrice From( - Models::NewFloatingTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - >) -)] -public sealed record class NewFloatingPackageWithAllocationPrice( - Models::NewFloatingPackageWithAllocationPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingPackageWithAllocationPrice, - Models::NewFloatingPackageWithAllocationPrice - > -{ - public static NewFloatingPackageWithAllocationPrice From( - Models::NewFloatingPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewFloatingTieredPackageWithMinimumPrice( - Models::NewFloatingTieredPackageWithMinimumPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingTieredPackageWithMinimumPrice, - Models::NewFloatingTieredPackageWithMinimumPrice - > -{ - public static NewFloatingTieredPackageWithMinimumPrice From( - Models::NewFloatingTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithPercentPrice, - Models::NewFloatingUnitWithPercentPrice - >) -)] -public sealed record class NewFloatingUnitWithPercentPrice( - Models::NewFloatingUnitWithPercentPrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitWithPercentPrice From( - Models::NewFloatingUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - >) -)] -public sealed record class NewFloatingTieredWithProrationPrice( - Models::NewFloatingTieredWithProrationPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingTieredWithProrationPrice, - Models::NewFloatingTieredWithProrationPrice - > -{ - public static NewFloatingTieredWithProrationPrice From( - Models::NewFloatingTieredWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingUnitWithProrationPrice, - Models::NewFloatingUnitWithProrationPrice - >) -)] -public sealed record class NewFloatingUnitWithProrationPrice( - Models::NewFloatingUnitWithProrationPrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingUnitWithProrationPrice From( - Models::NewFloatingUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedAllocationPrice, - Models::NewFloatingGroupedAllocationPrice - >) -)] -public sealed record class NewFloatingGroupedAllocationPrice( - Models::NewFloatingGroupedAllocationPrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingGroupedAllocationPrice From( - Models::NewFloatingGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithProratedMinimumPrice( - Models::NewFloatingGroupedWithProratedMinimumPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingGroupedWithProratedMinimumPrice, - Models::NewFloatingGroupedWithProratedMinimumPrice - > -{ - public static NewFloatingGroupedWithProratedMinimumPrice From( - Models::NewFloatingGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewFloatingGroupedWithMeteredMinimumPrice( - Models::NewFloatingGroupedWithMeteredMinimumPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingGroupedWithMeteredMinimumPrice, - Models::NewFloatingGroupedWithMeteredMinimumPrice - > -{ - public static NewFloatingGroupedWithMeteredMinimumPrice From( - Models::NewFloatingGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewFloatingMatrixWithDisplayNamePrice( - Models::NewFloatingMatrixWithDisplayNamePrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingMatrixWithDisplayNamePrice, - Models::NewFloatingMatrixWithDisplayNamePrice - > -{ - public static NewFloatingMatrixWithDisplayNamePrice From( - Models::NewFloatingMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingBulkWithProrationPrice, - Models::NewFloatingBulkWithProrationPrice - >) -)] -public sealed record class NewFloatingBulkWithProrationPrice( - Models::NewFloatingBulkWithProrationPrice Value -) - : AddProperties::Price, - Orb::IVariant -{ - public static NewFloatingBulkWithProrationPrice From( - Models::NewFloatingBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - >) -)] -public sealed record class NewFloatingGroupedTieredPackagePrice( - Models::NewFloatingGroupedTieredPackagePrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingGroupedTieredPackagePrice, - Models::NewFloatingGroupedTieredPackagePrice - > -{ - public static NewFloatingGroupedTieredPackagePrice From( - Models::NewFloatingGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithUnitPricingPrice( - Models::NewFloatingScalableMatrixWithUnitPricingPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingScalableMatrixWithUnitPricingPrice, - Models::NewFloatingScalableMatrixWithUnitPricingPrice - > -{ - public static NewFloatingScalableMatrixWithUnitPricingPrice From( - Models::NewFloatingScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewFloatingScalableMatrixWithTieredPricingPrice( - Models::NewFloatingScalableMatrixWithTieredPricingPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingScalableMatrixWithTieredPricingPrice, - Models::NewFloatingScalableMatrixWithTieredPricingPrice - > -{ - public static NewFloatingScalableMatrixWithTieredPricingPrice From( - Models::NewFloatingScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewFloatingCumulativeGroupedBulkPrice( - Models::NewFloatingCumulativeGroupedBulkPrice Value -) - : AddProperties::Price, - Orb::IVariant< - NewFloatingCumulativeGroupedBulkPrice, - Models::NewFloatingCumulativeGroupedBulkPrice - > -{ - public static NewFloatingCumulativeGroupedBulkPrice From( - Models::NewFloatingCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/StartDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/StartDate.cs deleted file mode 100644 index 17a8cab1..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/StartDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using StartDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.StartDateVariants; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; - -/// -/// The start date of the price interval. This is the date that the price will start -/// billing on the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class StartDate -{ - internal StartDate() { } - - public static StartDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static StartDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/StartDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/StartDateVariants/All.cs deleted file mode 100644 index 1b299366..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/AddProperties/StartDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using AddProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.AddProperties.StartDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : AddProperties::StartDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : AddProperties::StartDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/Edit.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/Edit.cs deleted file mode 100644 index 4bdbbdb9..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/Edit.cs +++ /dev/null @@ -1,187 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using EditProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Edit : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price interval to edit. - /// - public required string PriceIntervalID - { - get - { - if (!this.Properties.TryGetValue("price_interval_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_interval_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_interval_id"); - } - set - { - this.Properties["price_interval_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The updated billing cycle day for this price interval. If not specified, the - /// billing cycle day will not be updated. Note that overlapping price intervals - /// must have the same billing cycle day. - /// - public long? BillingCycleDay - { - get - { - if (!this.Properties.TryGetValue("billing_cycle_day", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["billing_cycle_day"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The updated end date of this price interval. If not specified, the end date - /// will not be updated. - /// - public EditProperties::EndDate? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// An additional filter to apply to usage queries. This filter must be expressed - /// as a boolean [computed property](/extensibility/advanced-metrics#computed-properties). - /// If null, usage queries will not include any additional filter. - /// - public string? Filter - { - get - { - if (!this.Properties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["filter"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A list of fixed fee quantity transitions to use for this price interval. Note - /// that this list will overwrite all existing fixed fee quantity transitions on - /// the price interval. - /// - public Generic::List? FixedFeeQuantityTransitions - { - get - { - if ( - !this.Properties.TryGetValue( - "fixed_fee_quantity_transitions", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.Properties["fixed_fee_quantity_transitions"] = - Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The updated start date of this price interval. If not specified, the start - /// date will not be updated. - /// - public EditProperties::StartDate? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// A list of customer IDs whose usage events will be aggregated and billed under - /// this subscription. By default, a subscription only considers usage events associated - /// with its attached customer's customer_id. When usage_customer_ids is provided, - /// the subscription includes usage events from the specified customers only. Provided - /// usage_customer_ids must be either the customer for this subscription itself, - /// or any of that customer's children. - /// - public Generic::List? UsageCustomerIDs - { - get - { - if (!this.Properties.TryGetValue("usage_customer_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - _ = this.PriceIntervalID; - _ = this.BillingCycleDay; - this.EndDate?.Validate(); - _ = this.Filter; - foreach (var item in this.FixedFeeQuantityTransitions ?? []) - { - item.Validate(); - } - this.StartDate?.Validate(); - foreach (var item in this.UsageCustomerIDs ?? []) - { - _ = item; - } - } - - public Edit() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Edit(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Edit FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustment.cs deleted file mode 100644 index 401b8b48..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustment.cs +++ /dev/null @@ -1,98 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using EditAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class EditAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the adjustment interval to edit. - /// - public required string AdjustmentIntervalID - { - get - { - if ( - !this.Properties.TryGetValue( - "adjustment_interval_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "adjustment_interval_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_interval_id"); - } - set - { - this.Properties["adjustment_interval_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// The updated end date of this adjustment interval. If not specified, the end - /// date will not be updated. - /// - public EditAdjustmentProperties::EndDate? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The updated start date of this adjustment interval. If not specified, the start - /// date will not be updated. - /// - public EditAdjustmentProperties::StartDate? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AdjustmentIntervalID; - this.EndDate?.Validate(); - this.StartDate?.Validate(); - } - - public EditAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - EditAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static EditAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/EndDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/EndDate.cs deleted file mode 100644 index 20f5d933..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/EndDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using EndDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties.EndDateVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties; - -/// -/// The updated end date of this adjustment interval. If not specified, the end date -/// will not be updated. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class EndDate -{ - internal EndDate() { } - - public static EndDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static EndDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/EndDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/EndDateVariants/All.cs deleted file mode 100644 index 0607b7c7..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/EndDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using EditAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties.EndDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : EditAdjustmentProperties::EndDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : EditAdjustmentProperties::EndDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/StartDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/StartDate.cs deleted file mode 100644 index b1e7bfad..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/StartDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using StartDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties.StartDateVariants; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties; - -/// -/// The updated start date of this adjustment interval. If not specified, the start -/// date will not be updated. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class StartDate -{ - internal StartDate() { } - - public static StartDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static StartDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/StartDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/StartDateVariants/All.cs deleted file mode 100644 index 1c56f39d..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditAdjustmentProperties/StartDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using EditAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditAdjustmentProperties.StartDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : EditAdjustmentProperties::StartDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : EditAdjustmentProperties::StartDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/EndDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/EndDate.cs deleted file mode 100644 index 1881c253..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/EndDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using EndDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties.EndDateVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; - -/// -/// The updated end date of this price interval. If not specified, the end date will -/// not be updated. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class EndDate -{ - internal EndDate() { } - - public static EndDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static EndDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/EndDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/EndDateVariants/All.cs deleted file mode 100644 index f03b9b91..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/EndDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using EditProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties.EndDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : EditProperties::EndDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : EditProperties::EndDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/FixedFeeQuantityTransition.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/FixedFeeQuantityTransition.cs deleted file mode 100644 index 008c7be2..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/FixedFeeQuantityTransition.cs +++ /dev/null @@ -1,73 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class FixedFeeQuantityTransition - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The date that the fixed fee quantity transition should take effect. - /// - public required System::DateTime EffectiveDate - { - get - { - if (!this.Properties.TryGetValue("effective_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "effective_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The quantity of the fixed fee quantity transition. - /// - public required long Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.EffectiveDate; - _ = this.Quantity; - } - - public FixedFeeQuantityTransition() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - FixedFeeQuantityTransition(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static FixedFeeQuantityTransition FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/StartDate.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/StartDate.cs deleted file mode 100644 index 9e83938d..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/StartDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using StartDateVariants = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties.StartDateVariants; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; - -/// -/// The updated start date of this price interval. If not specified, the start date -/// will not be updated. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class StartDate -{ - internal StartDate() { } - - public static StartDateVariants::DateTime Create(System::DateTime value) => new(value); - - public static StartDateVariants::BillingCycleRelativeDate Create( - Models::BillingCycleRelativeDate value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/StartDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/StartDateVariants/All.cs deleted file mode 100644 index a88151a6..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionPriceIntervalsParamsProperties/EditProperties/StartDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using EditProperties = Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionPriceIntervalsParamsProperties.EditProperties.StartDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class DateTime(System::DateTime Value) - : EditProperties::StartDate, - Orb::IVariant -{ - public static DateTime From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class BillingCycleRelativeDate(Models::BillingCycleRelativeDate Value) - : EditProperties::StartDate, - Orb::IVariant -{ - public static BillingCycleRelativeDate From(Models::BillingCycleRelativeDate value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionProperties/DiscountInterval.cs b/src/Orb/Models/Subscriptions/SubscriptionProperties/DiscountInterval.cs deleted file mode 100644 index 91af98b2..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionProperties/DiscountInterval.cs +++ /dev/null @@ -1,26 +0,0 @@ -using DiscountIntervalVariants = Orb.Models.Subscriptions.SubscriptionProperties.DiscountIntervalVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionProperties; - -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class DiscountInterval -{ - internal DiscountInterval() { } - - public static DiscountIntervalVariants::AmountDiscountInterval Create( - Models::AmountDiscountInterval value - ) => new(value); - - public static DiscountIntervalVariants::PercentageDiscountInterval Create( - Models::PercentageDiscountInterval value - ) => new(value); - - public static DiscountIntervalVariants::UsageDiscountInterval Create( - Models::UsageDiscountInterval value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionProperties/DiscountIntervalVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionProperties/DiscountIntervalVariants/All.cs deleted file mode 100644 index c37064c4..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionProperties/DiscountIntervalVariants/All.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionProperties = Orb.Models.Subscriptions.SubscriptionProperties; - -namespace Orb.Models.Subscriptions.SubscriptionProperties.DiscountIntervalVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class AmountDiscountInterval(Models::AmountDiscountInterval Value) - : SubscriptionProperties::DiscountInterval, - Orb::IVariant -{ - public static AmountDiscountInterval From(Models::AmountDiscountInterval value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class PercentageDiscountInterval(Models::PercentageDiscountInterval Value) - : SubscriptionProperties::DiscountInterval, - Orb::IVariant -{ - public static PercentageDiscountInterval From(Models::PercentageDiscountInterval value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UsageDiscountInterval(Models::UsageDiscountInterval Value) - : SubscriptionProperties::DiscountInterval, - Orb::IVariant -{ - public static UsageDiscountInterval From(Models::UsageDiscountInterval value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionProperties/Status.cs b/src/Orb/Models/Subscriptions/SubscriptionProperties/Status.cs deleted file mode 100644 index 8296f7d6..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionProperties/Status.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Status(string value) : Orb::IEnum -{ - public static readonly Status Active = new("active"); - - public static readonly Status Ended = new("ended"); - - public static readonly Status Upcoming = new("upcoming"); - - readonly string _value = value; - - public enum Value - { - Active, - Ended, - Upcoming, - } - - public Value Known() => - _value switch - { - "active" => Value.Active, - "ended" => Value.Ended, - "upcoming" => Value.Upcoming, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Status FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParams.cs b/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParams.cs index 006c7ba4..c83f4fe6 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParams.cs @@ -1,40 +1,39 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionRedeemCouponParamsProperties = Orb.Models.Subscriptions.SubscriptionRedeemCouponParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; /// /// Redeem a coupon effective at a given time. /// -public sealed record class SubscriptionRedeemCouponParams : Orb::ParamsBase +public sealed record class SubscriptionRedeemCouponParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } - public required SubscriptionRedeemCouponParamsProperties::ChangeOption ChangeOption + public required ApiEnum ChangeOption { get { - if (!this.BodyProperties.TryGetValue("change_option", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "change_option", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("change_option"); - } - set - { - this.BodyProperties["change_option"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawBodyData, + "change_option" + ); } + init { JsonModel.Set(this._rawBodyData, "change_option", value); } } /// @@ -46,37 +45,28 @@ public bool? AllowInvoiceCreditOrVoid { get { - if ( - !this.BodyProperties.TryGetValue( - "allow_invoice_credit_or_void", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["allow_invoice_credit_or_void"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "allow_invoice_credit_or_void" + ); } + init { JsonModel.Set(this._rawBodyData, "allow_invoice_credit_or_void", value); } } /// - /// The date that the coupon discount should take effect. This parameter can only - /// be passed if the `change_option` is `requested_date`. + /// The date that the coupon discount should take effect. This parameter can + /// only be passed if the `change_option` is `requested_date`. /// - public System::DateTime? ChangeDate + public System::DateTimeOffset? ChangeDate { get { - if (!this.BodyProperties.TryGetValue("change_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "change_date" + ); } - set { this.BodyProperties["change_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "change_date", value); } } /// @@ -84,14 +74,8 @@ public bool? AllowInvoiceCreditOrVoid /// public string? CouponID { - get - { - if (!this.BodyProperties.TryGetValue("coupon_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["coupon_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "coupon_id"); } + init { JsonModel.Set(this._rawBodyData, "coupon_id", value); } } /// @@ -101,50 +85,133 @@ public string? CouponRedemptionCode { get { - if ( - !this.BodyProperties.TryGetValue( - "coupon_redemption_code", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["coupon_redemption_code"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawBodyData, "coupon_redemption_code"); } + init { JsonModel.Set(this._rawBodyData, "coupon_redemption_code", value); } } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionRedeemCouponParams() { } + + public SubscriptionRedeemCouponParams( + SubscriptionRedeemCouponParams subscriptionRedeemCouponParams + ) + : base(subscriptionRedeemCouponParams) + { + this._rawBodyData = [.. subscriptionRedeemCouponParams._rawBodyData]; + } + + public SubscriptionRedeemCouponParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionRedeemCouponParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionRedeemCouponParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/redeem_coupon", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +[JsonConverter(typeof(ChangeOptionConverter))] +public enum ChangeOption +{ + RequestedDate, + EndOfSubscriptionTerm, + Immediate, +} + +sealed class ChangeOptionConverter : JsonConverter +{ + public override ChangeOption Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "requested_date" => ChangeOption.RequestedDate, + "end_of_subscription_term" => ChangeOption.EndOfSubscriptionTerm, + "immediate" => ChangeOption.Immediate, + _ => (ChangeOption)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ChangeOption value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ChangeOption.RequestedDate => "requested_date", + ChangeOption.EndOfSubscriptionTerm => "end_of_subscription_term", + ChangeOption.Immediate => "immediate", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParamsProperties/ChangeOption.cs b/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParamsProperties/ChangeOption.cs deleted file mode 100644 index ee890584..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionRedeemCouponParamsProperties/ChangeOption.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionRedeemCouponParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ChangeOption(string value) : Orb::IEnum -{ - public static readonly ChangeOption RequestedDate = new("requested_date"); - - public static readonly ChangeOption EndOfSubscriptionTerm = new("end_of_subscription_term"); - - public static readonly ChangeOption Immediate = new("immediate"); - - readonly string _value = value; - - public enum Value - { - RequestedDate, - EndOfSubscriptionTerm, - Immediate, - } - - public Value Known() => - _value switch - { - "requested_date" => Value.RequestedDate, - "end_of_subscription_term" => Value.EndOfSubscriptionTerm, - "immediate" => Value.Immediate, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ChangeOption FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParams.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParams.cs index 2e46e288..55e54f9b 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParams.cs @@ -1,11 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using SubscriptionSchedulePlanChangeParamsProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; @@ -13,248 +15,226 @@ namespace Orb.Models.Subscriptions; /// This endpoint can be used to change an existing subscription's plan. It returns /// the serialized updated subscription object. /// -/// The body parameter `change_option` determines when the plan change occurrs. Orb -/// supports three options: - `end_of_subscription_term`: changes the plan at the -/// end of the existing plan's term. - Issuing this plan change request for a -/// monthly subscription will keep the existing plan active until the start -/// of the subsequent month. Issuing this plan change request for a yearly subscription -/// will keep the existing plan active for the full year. Charges incurred -/// in the remaining period will be invoiced as normal. - Example: The plan is -/// billed monthly on the 1st of the month, the request is made on January 15th, so -/// the plan will be changed on February 1st, and invoice will be issued on -/// February 1st for the last month of the original plan. - `immediate`: changes the -/// plan immediately. - Subscriptions that have their plan changed with this option +/// The body parameter `change_option` determines when the plan change occurs. +/// Orb supports three options: - `end_of_subscription_term`: changes the plan at +/// the end of the existing plan's term. - Issuing this plan change request for +/// a monthly subscription will keep the existing plan active until the start +/// of the subsequent month. Issuing this plan change request for a yearly subscription +/// will keep the existing plan active for the full year. Charges incurred in +/// the remaining period will be invoiced as normal. - Example: The plan is billed +/// monthly on the 1st of the month, the request is made on January 15th, so the +/// plan will be changed on February 1st, and invoice will be issued on February +/// 1st for the last month of the original plan. - `immediate`: changes the plan +/// immediately. - Subscriptions that have their plan changed with this option /// will move to the new plan immediately, and be invoiced immediately. -/// - This invoice will include any usage fees incurred in the billing period up to -/// the change, along with any prorated recurring fees for the billing period, +/// - This invoice will include any usage fees incurred in the billing period up +/// to the change, along with any prorated recurring fees for the billing period, /// if applicable. - Example: The plan is billed monthly on the 1st of the month, /// the request is made on January 15th, so the plan will be changed on January -/// 15th, and an invoice will be issued for the partial month, from January 1 to January -/// 15, on the original plan. - `requested_date`: changes the plan on the requested -/// date (`change_date`). - If no timezone is provided, the customer's timezone -/// is used. The `change_date` body parameter is required if this option is -/// chosen. - Example: The plan is billed monthly on the 1st of the month, the -/// request is made on January 15th, with a requested `change_date` of February -/// 15th, so the plan will be changed on February 15th, and invoices will be issued -/// on February 1st and February 15th. +/// 15th, and an invoice will be issued for the partial month, from January 1 to +/// January 15, on the original plan. - `requested_date`: changes the plan on +/// the requested date (`change_date`). - If no timezone is provided, the customer's +/// timezone is used. The `change_date` body parameter is required if this option +/// is chosen. - Example: The plan is billed monthly on the 1st of the +/// month, the request is made on January 15th, with a requested `change_date` +/// of February 15th, so the plan will be changed on February 15th, and invoices +/// will be issued on February 1st and February 15th. /// -/// Note that one of `plan_id` or `external_plan_id` is required in the request body -/// for this operation. +/// Note that one of `plan_id` or `external_plan_id` is required in the request +/// body for this operation. /// -/// ## Customize your customer's subscriptions +/// ## Customize your customer's subscriptions /// -/// Prices and adjustments in a plan can be added, removed, or replaced on the subscription -/// when you schedule the plan change. This is useful when a customer has prices -/// that differ from the default prices for a specific plan. +/// Prices and adjustments in a plan can be added, removed, or replaced on the +/// subscription when you schedule the plan change. This is useful when a customer +/// has prices that differ from the default prices for a specific plan. /// -/// This feature is only available for accounts that have migrated to Subscription -/// Overrides Version 2. You can find your Subscription Overrides Version at the -/// bottom of your [Plans page](https://app.withorb.com/plans) +/// This feature is only available for accounts that have migrated to +/// Subscription Overrides Version 2. You can find your Subscription Overrides Version +/// at the bottom of your [Plans page](https://app.withorb.com/plans) /// -/// ### Adding Prices +/// ### Adding Prices /// -/// To add prices, provide a list of objects with the key `add_prices`. An object +/// To add prices, provide a list of objects with the key `add_prices`. An object /// in the list must specify an existing add-on price with a `price_id` or `external_price_id` /// field, or create a new add-on price by including an object with the key `price`, /// identical to what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). /// See the [Price resource](/product-catalog/price-configuration) for the specification -/// of different price model configurations possible in this object. +/// of different price model configurations possible in this object. /// -/// If the plan has phases, each object in the list must include a number with `plan_phase_order` -/// key to indicate which phase the price should be added to. +/// If the plan has phases, each object in the list must include a number with +/// `plan_phase_order` key to indicate which phase the price should be added to. /// -/// An object in the list can specify an optional `start_date` and optional `end_date`. -/// If `start_date` is unspecified, the start of the phase / plan change time will -/// be used. If `end_date` is unspecified, it will finish at the end of the phase -/// / have no end time. +/// An object in the list can specify an optional `start_date` and optional +/// `end_date`. If `start_date` is unspecified, the start of the phase / plan change +/// time will be used. If `end_date` is unspecified, it will finish at the end of +/// the phase / have no end time. /// -/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, -/// or `discounts`. This will create adjustments which apply only to this price. +/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, +/// or `discounts`. This will create adjustments which apply only to this price. /// -/// Additionally, an object in the list can specify an optional `reference_id`. This -/// ID can be used to reference this price when [adding an adjustment](#adding-adjustments) +/// Additionally, an object in the list can specify an optional `reference_id`. +/// This ID can be used to reference this price when [adding an adjustment](#adding-adjustments) /// in the same API call. However the ID is _transient_ and cannot be used to refer -/// to the price in future API calls. +/// to the price in future API calls. /// -/// ### Removing Prices +/// ### Removing Prices /// -/// To remove prices, provide a list of objects with the key `remove_prices`. An -/// object in the list must specify a plan price with either a `price_id` or `external_price_id` field. +/// To remove prices, provide a list of objects with the key `remove_prices`. +/// An object in the list must specify a plan price with either a `price_id` or `external_price_id` field. /// -/// ### Replacing Prices +/// ### Replacing Prices /// -/// To replace prices, provide a list of objects with the key `replace_prices`. An -/// object in the list must specify a plan price to replace with the `replaces_price_id` -/// key, and it must specify a price to replace it with by either referencing an existing -/// add-on price with a `price_id` or `external_price_id` field, or by creating a -/// new add-on price by including an object with the key `price`, identical to what -/// would be used in the request body for the [create price endpoint](/api-reference/price/create-price). +/// To replace prices, provide a list of objects with the key `replace_prices`. +/// An object in the list must specify a plan price to replace with the `replaces_price_id` +/// key, and it must specify a price to replace it with by either referencing an +/// existing add-on price with a `price_id` or `external_price_id` field, or by creating +/// a new add-on price by including an object with the key `price`, identical to +/// what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). /// See the [Price resource](/product-catalog/price-configuration) for the specification -/// of different price model configurations possible in this object. +/// of different price model configurations possible in this object. /// -/// For fixed fees, an object in the list can supply a `fixed_price_quantity` instead -/// of a `price`, `price_id`, or `external_price_id` field. This will update only -/// the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. +/// For fixed fees, an object in the list can supply a `fixed_price_quantity` +/// instead of a `price`, `price_id`, or `external_price_id` field. This will update +/// only the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. /// -/// The replacement price will have the same phase, if applicable, and the same start -/// and end dates as the price it replaces. +/// The replacement price will have the same phase, if applicable, and the +/// same start and end dates as the price it replaces. /// -/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, -/// or `discounts`. This will create adjustments which apply only to this price. +/// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, +/// or `discounts`. This will create adjustments which apply only to this price. /// -/// Additionally, an object in the list can specify an optional `reference_id`. This -/// ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) +/// Additionally, an object in the list can specify an optional `reference_id`. +/// This ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) /// in the same API call. However the ID is _transient_ and cannot be used to refer -/// to the price in future API calls. +/// to the price in future API calls. /// -/// ### Adding adjustments +/// ### Adding adjustments /// -/// To add adjustments, provide a list of objects with the key `add_adjustments`. +/// To add adjustments, provide a list of objects with the key `add_adjustments`. /// An object in the list must include an object with the key `adjustment`, identical -/// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). +/// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). /// -/// If the plan has phases, each object in the list must include a number with `plan_phase_order` -/// key to indicate which phase the adjustment should be added to. +/// If the plan has phases, each object in the list must include a number with +/// `plan_phase_order` key to indicate which phase the adjustment should be added to. /// -/// An object in the list can specify an optional `start_date` and optional `end_date`. -/// If `start_date` is unspecified, the start of the phase / plan change time will -/// be used. If `end_date` is unspecified, it will finish at the end of the phase -/// / have no end time. +/// An object in the list can specify an optional `start_date` and optional +/// `end_date`. If `start_date` is unspecified, the start of the phase / plan change +/// time will be used. If `end_date` is unspecified, it will finish at the end of +/// the phase / have no end time. /// -/// ### Removing adjustments +/// ### Removing adjustments /// -/// To remove adjustments, provide a list of objects with the key `remove_adjustments`. +/// To remove adjustments, provide a list of objects with the key `remove_adjustments`. /// An object in the list must include a key, `adjustment_id`, with the ID of the -/// adjustment to be removed. +/// adjustment to be removed. /// -/// ### Replacing adjustments +/// ### Replacing adjustments /// -/// To replace adjustments, provide a list of objects with the key `replace_adjustments`. +/// To replace adjustments, provide a list of objects with the key `replace_adjustments`. /// An object in the list must specify a plan adjustment to replace with the `replaces_adjustment_id` /// key, and it must specify an adjustment to replace it with by including an object /// with the key `adjustment`, identical to the adjustment object in the [add/edit -/// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). +/// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). /// -/// The replacement adjustment will have the same phase, if applicable, and the same -/// start and end dates as the adjustment it replaces. +/// The replacement adjustment will have the same phase, if applicable, and +/// the same start and end dates as the adjustment it replaces. /// -/// ## Price overrides (DEPRECATED) +/// ## Price overrides (DEPRECATED) /// -/// Price overrides are being phased out in favor adding/removing/replacing -/// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/schedule-plan-change)) +/// Price overrides are being phased out in favor adding/removing/replacing +/// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/schedule-plan-change)) /// -/// Price overrides are used to update some or all prices in a plan for the specific -/// subscription being created. This is useful when a new customer has negotiated -/// a rate that is unique to the customer. +/// Price overrides are used to update some or all prices in a plan for the +/// specific subscription being created. This is useful when a new customer has negotiated +/// a rate that is unique to the customer. /// -/// To override prices, provide a list of objects with the key `price_overrides`. +/// To override prices, provide a list of objects with the key `price_overrides`. /// The price object in the list of overrides is expected to contain the existing /// price id, the `model_type` and configuration. (See the [Price resource](/product-catalog/price-configuration) /// for the specification of different price model configurations.) The numerical -/// values can be updated, but the billable metric, cadence, type, and name of a price -/// can not be overridden. +/// values can be updated, but the billable metric, cadence, type, and name of a +/// price can not be overridden. /// -/// ### Maximums, and minimums Price overrides are used to update some or all prices -/// in the target plan. Minimums and maximums, much like price overrides, can be -/// useful when a new customer has negotiated a new or different minimum or maximum -/// spend cap than the default for the plan. The request format for maximums and -/// minimums is the same as those in [subscription creation](create-subscription). +/// ### Maximums, and minimums Price overrides are used to update some or all +/// prices in the target plan. Minimums and maximums, much like price overrides, can +/// be useful when a new customer has negotiated a new or different minimum or maximum +/// spend cap than the default for the plan. The request format for maximums and minimums +/// is the same as those in [subscription creation](create-subscription). /// -/// ## Scheduling multiple plan changes When scheduling multiple plan changes with -/// the same date, the latest plan change on that day takes effect. +/// ## Scheduling multiple plan changes When scheduling multiple plan changes +/// with the same date, the latest plan change on that day takes effect. /// -/// ## Prorations for in-advance fees By default, Orb calculates the prorated difference -/// in any fixed fees when making a plan change, adjusting the customer balance as -/// needed. For details on this behavior, see [Modifying subscriptions](/product-catalog/modifying-subscriptions#prorations-for-in-advance-fees). +/// ## Prorations for in-advance fees By default, Orb calculates the prorated +/// difference in any fixed fees when making a plan change, adjusting the customer +/// balance as needed. For details on this behavior, see [Modifying subscriptions](/product-catalog/modifying-subscriptions#prorations-for-in-advance-fees). /// -public sealed record class SubscriptionSchedulePlanChangeParams : Orb::ParamsBase +public sealed record class SubscriptionSchedulePlanChangeParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } - public required SubscriptionSchedulePlanChangeParamsProperties::ChangeOption ChangeOption + public required ApiEnum ChangeOption { get { - if (!this.BodyProperties.TryGetValue("change_option", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "change_option", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("change_option"); - } - set - { - this.BodyProperties["change_option"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawBodyData, "change_option"); } + init { JsonModel.Set(this._rawBodyData, "change_option", value); } } /// /// Additional adjustments to be added to the subscription. (Only available for /// accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? AddAdjustments + public IReadOnlyList? AddAdjustments { get { - if (!this.BodyProperties.TryGetValue("add_adjustments", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["add_adjustments"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "add_adjustments"); } + init { JsonModel.Set(this._rawBodyData, "add_adjustments", value); } } /// /// Additional prices to be added to the subscription. (Only available for accounts /// that have migrated off of legacy subscription overrides) /// - public Generic::List? AddPrices + public IReadOnlyList? AddPrices { get { - if (!this.BodyProperties.TryGetValue("add_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "add_prices" ); } - set { this.BodyProperties["add_prices"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "add_prices", value); } } /// - /// [DEPRECATED] Use billing_cycle_alignment instead. Reset billing periods to be - /// aligned with the plan change's effective date. + /// [DEPRECATED] Use billing_cycle_alignment instead. Reset billing periods to + /// be aligned with the plan change's effective date. /// public bool? AlignBillingWithPlanChangeDate { get { - if ( - !this.BodyProperties.TryGetValue( - "align_billing_with_plan_change_date", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["align_billing_with_plan_change_date"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "align_billing_with_plan_change_date" + ); } + init { JsonModel.Set(this._rawBodyData, "align_billing_with_plan_change_date", value); } } /// @@ -264,160 +244,88 @@ public bool? AlignBillingWithPlanChangeDate /// public bool? AutoCollection { - get - { - if (!this.BodyProperties.TryGetValue("auto_collection", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_collection"); } + init { JsonModel.Set(this._rawBodyData, "auto_collection", value); } } /// - /// Reset billing periods to be aligned with the plan change's effective date or - /// start of the month. Defaults to `unchanged` which keeps subscription's existing - /// billing cycle alignment. + /// Reset billing periods to be aligned with the plan change's effective date + /// or start of the month. Defaults to `unchanged` which keeps subscription's + /// existing billing cycle alignment. /// - public SubscriptionSchedulePlanChangeParamsProperties::BillingCycleAlignment? BillingCycleAlignment + public ApiEnum? BillingCycleAlignment { get { - if ( - !this.BodyProperties.TryGetValue( - "billing_cycle_alignment", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass>( + this.RawBodyData, + "billing_cycle_alignment" ); } - set - { - this.BodyProperties["billing_cycle_alignment"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawBodyData, "billing_cycle_alignment", value); } } - public Models::BillingCycleAnchorConfiguration? BillingCycleAnchorConfiguration + public BillingCycleAnchorConfiguration? BillingCycleAnchorConfiguration { get { - if ( - !this.BodyProperties.TryGetValue( - "billing_cycle_anchor_configuration", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize( - element + return JsonModel.GetNullableClass( + this.RawBodyData, + "billing_cycle_anchor_configuration" ); } - set - { - this.BodyProperties["billing_cycle_anchor_configuration"] = - Json::JsonSerializer.SerializeToElement(value); - } + init { JsonModel.Set(this._rawBodyData, "billing_cycle_anchor_configuration", value); } } /// - /// The date that the plan change should take effect. This parameter can only be - /// passed if the `change_option` is `requested_date`. If a date with no time is - /// passed, the plan change will happen at midnight in the customer's timezone. + /// The date that the plan change should take effect. This parameter can only + /// be passed if the `change_option` is `requested_date`. If a date with no time + /// is passed, the plan change will happen at midnight in the customer's timezone. /// - public System::DateTime? ChangeDate + public System::DateTimeOffset? ChangeDate { get { - if (!this.BodyProperties.TryGetValue("change_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "change_date" + ); } - set { this.BodyProperties["change_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "change_date", value); } } /// - /// Redemption code to be used for this subscription. If the coupon cannot be found - /// by its redemption code, or cannot be redeemed, an error response will be returned - /// and the subscription creation or plan change will not be scheduled. + /// Redemption code to be used for this subscription. If the coupon cannot be + /// found by its redemption code, or cannot be redeemed, an error response will + /// be returned and the subscription creation or plan change will not be scheduled. /// public string? CouponRedemptionCode { get { - if ( - !this.BodyProperties.TryGetValue( - "coupon_redemption_code", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["coupon_redemption_code"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass(this.RawBodyData, "coupon_redemption_code"); } + init { JsonModel.Set(this._rawBodyData, "coupon_redemption_code", value); } } + [System::Obsolete("deprecated")] public double? CreditsOverageRate { get { - if ( - !this.BodyProperties.TryGetValue( - "credits_overage_rate", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["credits_overage_rate"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableStruct(this.RawBodyData, "credits_overage_rate"); } + init { JsonModel.Set(this._rawBodyData, "credits_overage_rate", value); } } /// - /// Determines the default memo on this subscription's invoices. Note that if this - /// is not provided, it is determined by the plan configuration. + /// Determines the default memo on this subscription's invoices. Note that if + /// this is not provided, it is determined by the plan configuration. /// public string? DefaultInvoiceMemo { - get - { - if ( - !this.BodyProperties.TryGetValue( - "default_invoice_memo", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawBodyData, "default_invoice_memo", value); } } /// @@ -426,19 +334,8 @@ public string? DefaultInvoiceMemo /// public string? ExternalPlanID { - get - { - if (!this.BodyProperties.TryGetValue("external_plan_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["external_plan_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "external_plan_id"); } + init { JsonModel.Set(this._rawBodyData, "external_plan_id", value); } } /// @@ -448,14 +345,8 @@ public string? ExternalPlanID /// public string? Filter { - get - { - if (!this.BodyProperties.TryGetValue("filter", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["filter"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "filter"); } + init { JsonModel.Set(this._rawBodyData, "filter", value); } } /// @@ -463,89 +354,43 @@ public string? Filter /// public long? InitialPhaseOrder { - get - { - if ( - !this.BodyProperties.TryGetValue( - "initial_phase_order", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["initial_phase_order"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "initial_phase_order"); } + init { JsonModel.Set(this._rawBodyData, "initial_phase_order", value); } } /// - /// When this subscription's accrued usage reaches this threshold, an invoice will - /// be issued for the subscription. If not specified, invoices will only be issued - /// at the end of the billing period. + /// When this subscription's accrued usage reaches this threshold, an invoice + /// will be issued for the subscription. If not specified, invoices will only + /// be issued at the end of the billing period. /// public string? InvoicingThreshold { - get - { - if ( - !this.BodyProperties.TryGetValue( - "invoicing_threshold", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["invoicing_threshold"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "invoicing_threshold"); } + init { JsonModel.Set(this._rawBodyData, "invoicing_threshold", value); } } /// - /// The net terms determines the difference between the invoice date and the issue - /// date for the invoice. If you intend the invoice to be due on issue, set this - /// to 0. If not provided, this defaults to the value specified in the plan. + /// The net terms determines the difference between the invoice date and the + /// issue date for the invoice. If you intend the invoice to be due on issue, + /// set this to 0. If not provided, this defaults to the value specified in the plan. /// public long? NetTerms { - get - { - if (!this.BodyProperties.TryGetValue("net_terms", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "net_terms"); } + init { JsonModel.Set(this._rawBodyData, "net_terms", value); } } + [System::Obsolete("deprecated")] public double? PerCreditOverageAmount { get { - if ( - !this.BodyProperties.TryGetValue( - "per_credit_overage_amount", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["per_credit_overage_amount"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "per_credit_overage_amount" + ); } + init { JsonModel.Set(this._rawBodyData, "per_credit_overage_amount", value); } } /// @@ -554,14 +399,8 @@ public double? PerCreditOverageAmount /// public string? PlanID { - get - { - if (!this.BodyProperties.TryGetValue("plan_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["plan_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawBodyData, "plan_id"); } + init { JsonModel.Set(this._rawBodyData, "plan_id", value); } } /// @@ -570,140 +409,84 @@ public string? PlanID /// public long? PlanVersionNumber { - get - { - if ( - !this.BodyProperties.TryGetValue( - "plan_version_number", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["plan_version_number"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "plan_version_number"); } + init { JsonModel.Set(this._rawBodyData, "plan_version_number", value); } } /// /// Optionally provide a list of overrides for prices on the plan /// - public Generic::List? PriceOverrides + [System::Obsolete("deprecated")] + public IReadOnlyList? PriceOverrides { get { - if (!this.BodyProperties.TryGetValue("price_overrides", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.BodyProperties["price_overrides"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "price_overrides" + ); } + init { JsonModel.Set(this._rawBodyData, "price_overrides", value); } } /// - /// Plan adjustments to be removed from the subscription. (Only available for accounts - /// that have migrated off of legacy subscription overrides) + /// Plan adjustments to be removed from the subscription. (Only available for + /// accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? RemoveAdjustments + public IReadOnlyList? RemoveAdjustments { get { - if ( - !this.BodyProperties.TryGetValue( - "remove_adjustments", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["remove_adjustments"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "remove_adjustments"); } + init { JsonModel.Set(this._rawBodyData, "remove_adjustments", value); } } /// /// Plan prices to be removed from the subscription. (Only available for accounts /// that have migrated off of legacy subscription overrides) /// - public Generic::List? RemovePrices + public IReadOnlyList? RemovePrices { get { - if (!this.BodyProperties.TryGetValue("remove_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["remove_prices"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "remove_prices"); } + init { JsonModel.Set(this._rawBodyData, "remove_prices", value); } } /// /// Plan adjustments to be replaced with additional adjustments on the subscription. /// (Only available for accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? ReplaceAdjustments + public IReadOnlyList? ReplaceAdjustments { get { - if ( - !this.BodyProperties.TryGetValue( - "replace_adjustments", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["replace_adjustments"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "replace_adjustments"); } + init { JsonModel.Set(this._rawBodyData, "replace_adjustments", value); } } /// /// Plan prices to be replaced with additional prices on the subscription. (Only /// available for accounts that have migrated off of legacy subscription overrides) /// - public Generic::List? ReplacePrices + public IReadOnlyList? ReplacePrices { get { - if (!this.BodyProperties.TryGetValue("replace_prices", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set - { - this.BodyProperties["replace_prices"] = Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableClass< + List + >(this.RawBodyData, "replace_prices"); } + init { JsonModel.Set(this._rawBodyData, "replace_prices", value); } } /// @@ -712,83 +495,17297 @@ public long? PlanVersionNumber /// will be skipped. /// public long? TrialDurationDays + { + get { return JsonModel.GetNullableStruct(this.RawBodyData, "trial_duration_days"); } + init { JsonModel.Set(this._rawBodyData, "trial_duration_days", value); } + } + + /// + /// A list of customer IDs whose usage events will be aggregated and billed under + /// this subscription. By default, a subscription only considers usage events + /// associated with its attached customer's customer_id. When usage_customer_ids + /// is provided, the subscription includes usage events from the specified customers + /// only. Provided usage_customer_ids must be either the customer for this subscription + /// itself, or any of that customer's children. + /// + public IReadOnlyList? UsageCustomerIDs { get { - if ( - !this.BodyProperties.TryGetValue( - "trial_duration_days", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableClass>(this.RawBodyData, "usage_customer_ids"); + } + init { JsonModel.Set(this._rawBodyData, "usage_customer_ids", value); } + } + + public SubscriptionSchedulePlanChangeParams() { } + + public SubscriptionSchedulePlanChangeParams( + SubscriptionSchedulePlanChangeParams subscriptionSchedulePlanChangeParams + ) + : base(subscriptionSchedulePlanChangeParams) + { + this._rawBodyData = [.. subscriptionSchedulePlanChangeParams._rawBodyData]; + } + + public SubscriptionSchedulePlanChangeParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) + { + return new System::UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + + string.Format("/subscriptions/{0}/schedule_plan_change", this.SubscriptionID) + ) + { + Query = this.QueryString(options), + }.Uri; + } + + internal override HttpContent? BodyContent() + { + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, + "application/json" + ); + } - return Json::JsonSerializer.Deserialize(element); + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } - set + } +} + +[JsonConverter(typeof(SubscriptionSchedulePlanChangeParamsChangeOptionConverter))] +public enum SubscriptionSchedulePlanChangeParamsChangeOption +{ + RequestedDate, + EndOfSubscriptionTerm, + Immediate, +} + +sealed class SubscriptionSchedulePlanChangeParamsChangeOptionConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsChangeOption Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch { - this.BodyProperties["trial_duration_days"] = Json::JsonSerializer.SerializeToElement( - value + "requested_date" => SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate, + "end_of_subscription_term" => + SubscriptionSchedulePlanChangeParamsChangeOption.EndOfSubscriptionTerm, + "immediate" => SubscriptionSchedulePlanChangeParamsChangeOption.Immediate, + _ => (SubscriptionSchedulePlanChangeParamsChangeOption)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsChangeOption value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsChangeOption.RequestedDate => "requested_date", + SubscriptionSchedulePlanChangeParamsChangeOption.EndOfSubscriptionTerm => + "end_of_subscription_term", + SubscriptionSchedulePlanChangeParamsChangeOption.Immediate => "immediate", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddAdjustment, + SubscriptionSchedulePlanChangeParamsAddAdjustmentFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the subscription. + /// + public required SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment Adjustment + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" ); } + init { JsonModel.Set(this._rawData, "adjustment", value); } } /// - /// A list of customer IDs whose usage events will be aggregated and billed under - /// this subscription. By default, a subscription only considers usage events associated - /// with its attached customer's customer_id. When usage_customer_ids is provided, - /// the subscription includes usage events from the specified customers only. Provided - /// usage_customer_ids must be either the customer for this subscription itself, - /// or any of that customer's children. + /// The end date of the adjustment interval. This is the date that the adjustment + /// will stop affecting prices on the subscription. /// - public Generic::List? UsageCustomerIDs + public System::DateTimeOffset? EndDate { get { - if ( - !this.BodyProperties.TryGetValue( - "usage_customer_ids", - out Json::JsonElement element - ) - ) - return null; + return JsonModel.GetNullableStruct(this.RawData, "end_date"); + } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// The phase to add this adjustment to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } - return Json::JsonSerializer.Deserialize?>(element); + /// + /// The start date of the adjustment interval. This is the date that the adjustment + /// will start affecting prices on the subscription. If null, the adjustment will + /// start when the phase or subscription starts. + /// + public System::DateTimeOffset? StartDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "start_date"); } - set + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.EndDate; + _ = this.PlanPhaseOrder; + _ = this.StartDate; + } + + public SubscriptionSchedulePlanChangeParamsAddAdjustment() { } + + public SubscriptionSchedulePlanChangeParamsAddAdjustment( + SubscriptionSchedulePlanChangeParamsAddAdjustment subscriptionSchedulePlanChangeParamsAddAdjustment + ) + : base(subscriptionSchedulePlanChangeParamsAddAdjustment) { } + + public SubscriptionSchedulePlanChangeParamsAddAdjustment( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddAdjustment(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsAddAdjustment( + SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment adjustment + ) + : this() + { + this.Adjustment = adjustment; + } +} + +class SubscriptionSchedulePlanChangeParamsAddAdjustmentFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsAddAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the subscription. +/// +[JsonConverter(typeof(SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustmentConverter))] +public record class SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get { - this.BodyProperties["usage_customer_ids"] = Json::JsonSerializer.SerializeToElement( - value + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency ); } } - public override System::Uri Url(Orb::IOrbClient client) + public bool? IsInvoiceLevel { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') - + string.Format("/subscriptions/{0}/schedule_plan_change", this.SubscriptionID) - ) + get { - Query = this.QueryString(client), - }.Uri; + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } } - public Http::StringContent BodyContent() + public SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewPercentageDiscount value, + JsonElement? element = null + ) { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, - "application/json" - ); + this.Value = value; + this._element = element; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + public SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewUsageDiscount value, + JsonElement? element = null + ) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) - { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); - } + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewAmountDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewMinimum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewMaximum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewUsageDiscount value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewAmountDiscount value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewMinimum value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment( + NewMaximum value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals(SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustmentConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddAdjustmentAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPrice, + SubscriptionSchedulePlanChangeParamsAddPriceFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPrice : JsonModel +{ + /// + /// The definition of a new allocation price to create and add to the subscription. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for + /// this price. + /// + [System::Obsolete("deprecated")] + public IReadOnlyList? Discounts + { + get + { + return JsonModel.GetNullableClass>(this.RawData, "discounts"); + } + init { JsonModel.Set(this._rawData, "discounts", value); } + } + + /// + /// The end date of the price interval. This is the date that the price will stop + /// billing on the subscription. If null, billing will end when the phase or subscription ends. + /// + public System::DateTimeOffset? EndDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "end_date"); + } + init { JsonModel.Set(this._rawData, "end_date", value); } + } + + /// + /// The external price id of the price to add to the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount + /// for this price. + /// + [System::Obsolete("deprecated")] + public string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount + /// for this price. + /// + [System::Obsolete("deprecated")] + public string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// The phase to add this price to. + /// + public long? PlanPhaseOrder + { + get { return JsonModel.GetNullableStruct(this.RawData, "plan_phase_order"); } + init { JsonModel.Set(this._rawData, "plan_phase_order", value); } + } + + /// + /// New subscription price request body params. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePrice? Price + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "price" + ); + } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// The id of the price to add to the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + /// The start date of the price interval. This is the date that the price will + /// start billing on the subscription. If null, billing will start when the phase + /// or subscription starts. + /// + public System::DateTimeOffset? StartDate + { + get + { + return JsonModel.GetNullableStruct(this.RawData, "start_date"); + } + init { JsonModel.Set(this._rawData, "start_date", value); } + } + + /// + public override void Validate() + { + this.AllocationPrice?.Validate(); + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + _ = this.EndDate; + _ = this.ExternalPriceID; + _ = this.MaximumAmount; + _ = this.MinimumAmount; + _ = this.PlanPhaseOrder; + this.Price?.Validate(); + _ = this.PriceID; + _ = this.StartDate; + } + + public SubscriptionSchedulePlanChangeParamsAddPrice() { } + + public SubscriptionSchedulePlanChangeParamsAddPrice( + SubscriptionSchedulePlanChangeParamsAddPrice subscriptionSchedulePlanChangeParamsAddPrice + ) + : base(subscriptionSchedulePlanChangeParamsAddPrice) { } + + public SubscriptionSchedulePlanChangeParamsAddPrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPriceFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsAddPrice.FromRawUnchecked(rawData); +} + +/// +/// New subscription price request body params. +/// +[JsonConverter(typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceConverter))] +public record class SubscriptionSchedulePlanChangeParamsAddPricePrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ItemID, + newSubscriptionTiered: (x) => x.ItemID, + newSubscriptionBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newSubscriptionPackage: (x) => x.ItemID, + newSubscriptionMatrix: (x) => x.ItemID, + newSubscriptionThresholdTotalAmount: (x) => x.ItemID, + newSubscriptionTieredPackage: (x) => x.ItemID, + newSubscriptionTieredWithMinimum: (x) => x.ItemID, + newSubscriptionGroupedTiered: (x) => x.ItemID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ItemID, + newSubscriptionPackageWithAllocation: (x) => x.ItemID, + newSubscriptionUnitWithPercent: (x) => x.ItemID, + newSubscriptionMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newSubscriptionUnitWithProration: (x) => x.ItemID, + newSubscriptionGroupedAllocation: (x) => x.ItemID, + newSubscriptionBulkWithProration: (x) => x.ItemID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ItemID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newSubscriptionMatrixWithDisplayName: (x) => x.ItemID, + newSubscriptionGroupedTieredPackage: (x) => x.ItemID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ItemID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ItemID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ItemID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newSubscriptionMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Name, + newSubscriptionTiered: (x) => x.Name, + newSubscriptionBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newSubscriptionPackage: (x) => x.Name, + newSubscriptionMatrix: (x) => x.Name, + newSubscriptionThresholdTotalAmount: (x) => x.Name, + newSubscriptionTieredPackage: (x) => x.Name, + newSubscriptionTieredWithMinimum: (x) => x.Name, + newSubscriptionGroupedTiered: (x) => x.Name, + newSubscriptionTieredPackageWithMinimum: (x) => x.Name, + newSubscriptionPackageWithAllocation: (x) => x.Name, + newSubscriptionUnitWithPercent: (x) => x.Name, + newSubscriptionMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newSubscriptionUnitWithProration: (x) => x.Name, + newSubscriptionGroupedAllocation: (x) => x.Name, + newSubscriptionBulkWithProration: (x) => x.Name, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Name, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newSubscriptionMatrixWithDisplayName: (x) => x.Name, + newSubscriptionGroupedTieredPackage: (x) => x.Name, + newSubscriptionMaxGroupTieredPackage: (x) => x.Name, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Name, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Name, + newSubscriptionCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newSubscriptionMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillableMetricID, + newSubscriptionTiered: (x) => x.BillableMetricID, + newSubscriptionBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newSubscriptionPackage: (x) => x.BillableMetricID, + newSubscriptionMatrix: (x) => x.BillableMetricID, + newSubscriptionThresholdTotalAmount: (x) => x.BillableMetricID, + newSubscriptionTieredPackage: (x) => x.BillableMetricID, + newSubscriptionTieredWithMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedTiered: (x) => x.BillableMetricID, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillableMetricID, + newSubscriptionPackageWithAllocation: (x) => x.BillableMetricID, + newSubscriptionUnitWithPercent: (x) => x.BillableMetricID, + newSubscriptionMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newSubscriptionUnitWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionBulkWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newSubscriptionMatrixWithDisplayName: (x) => x.BillableMetricID, + newSubscriptionGroupedTieredPackage: (x) => x.BillableMetricID, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BilledInAdvance, + newSubscriptionTiered: (x) => x.BilledInAdvance, + newSubscriptionBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newSubscriptionPackage: (x) => x.BilledInAdvance, + newSubscriptionMatrix: (x) => x.BilledInAdvance, + newSubscriptionThresholdTotalAmount: (x) => x.BilledInAdvance, + newSubscriptionTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionTieredWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedTiered: (x) => x.BilledInAdvance, + newSubscriptionTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionPackageWithAllocation: (x) => x.BilledInAdvance, + newSubscriptionUnitWithPercent: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newSubscriptionUnitWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionBulkWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithDisplayName: (x) => x.BilledInAdvance, + newSubscriptionGroupedTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newSubscriptionCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillingCycleConfiguration, + newSubscriptionTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newSubscriptionPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrix: (x) => x.BillingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ConversionRate, + newSubscriptionTiered: (x) => x.ConversionRate, + newSubscriptionBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newSubscriptionPackage: (x) => x.ConversionRate, + newSubscriptionMatrix: (x) => x.ConversionRate, + newSubscriptionThresholdTotalAmount: (x) => x.ConversionRate, + newSubscriptionTieredPackage: (x) => x.ConversionRate, + newSubscriptionTieredWithMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedTiered: (x) => x.ConversionRate, + newSubscriptionTieredPackageWithMinimum: (x) => x.ConversionRate, + newSubscriptionPackageWithAllocation: (x) => x.ConversionRate, + newSubscriptionUnitWithPercent: (x) => x.ConversionRate, + newSubscriptionMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newSubscriptionUnitWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionBulkWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newSubscriptionMatrixWithDisplayName: (x) => x.ConversionRate, + newSubscriptionGroupedTieredPackage: (x) => x.ConversionRate, + newSubscriptionMaxGroupTieredPackage: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newSubscriptionCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Currency, + newSubscriptionTiered: (x) => x.Currency, + newSubscriptionBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newSubscriptionPackage: (x) => x.Currency, + newSubscriptionMatrix: (x) => x.Currency, + newSubscriptionThresholdTotalAmount: (x) => x.Currency, + newSubscriptionTieredPackage: (x) => x.Currency, + newSubscriptionTieredWithMinimum: (x) => x.Currency, + newSubscriptionGroupedTiered: (x) => x.Currency, + newSubscriptionTieredPackageWithMinimum: (x) => x.Currency, + newSubscriptionPackageWithAllocation: (x) => x.Currency, + newSubscriptionUnitWithPercent: (x) => x.Currency, + newSubscriptionMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newSubscriptionUnitWithProration: (x) => x.Currency, + newSubscriptionGroupedAllocation: (x) => x.Currency, + newSubscriptionBulkWithProration: (x) => x.Currency, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Currency, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newSubscriptionMatrixWithDisplayName: (x) => x.Currency, + newSubscriptionGroupedTieredPackage: (x) => x.Currency, + newSubscriptionMaxGroupTieredPackage: (x) => x.Currency, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Currency, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Currency, + newSubscriptionCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newSubscriptionMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrix: (x) => x.DimensionalPriceConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ExternalPriceID, + newSubscriptionTiered: (x) => x.ExternalPriceID, + newSubscriptionBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newSubscriptionPackage: (x) => x.ExternalPriceID, + newSubscriptionMatrix: (x) => x.ExternalPriceID, + newSubscriptionThresholdTotalAmount: (x) => x.ExternalPriceID, + newSubscriptionTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionTieredWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedTiered: (x) => x.ExternalPriceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionPackageWithAllocation: (x) => x.ExternalPriceID, + newSubscriptionUnitWithPercent: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newSubscriptionUnitWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionBulkWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ExternalPriceID, + newSubscriptionGroupedTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newSubscriptionUnit: (x) => x.FixedPriceQuantity, + newSubscriptionTiered: (x) => x.FixedPriceQuantity, + newSubscriptionBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newSubscriptionPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMatrix: (x) => x.FixedPriceQuantity, + newSubscriptionThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionTieredWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTiered: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionPackageWithAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithPercent: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionBulkWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newSubscriptionCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoiceGroupingKey, + newSubscriptionTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newSubscriptionPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrix: (x) => x.InvoiceGroupingKey, + newSubscriptionThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithPercent: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionBulkWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrix: (x) => x.InvoicingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.InvoicingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ReferenceID, + newSubscriptionTiered: (x) => x.ReferenceID, + newSubscriptionBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newSubscriptionPackage: (x) => x.ReferenceID, + newSubscriptionMatrix: (x) => x.ReferenceID, + newSubscriptionThresholdTotalAmount: (x) => x.ReferenceID, + newSubscriptionTieredPackage: (x) => x.ReferenceID, + newSubscriptionTieredWithMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedTiered: (x) => x.ReferenceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ReferenceID, + newSubscriptionPackageWithAllocation: (x) => x.ReferenceID, + newSubscriptionUnitWithPercent: (x) => x.ReferenceID, + newSubscriptionMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newSubscriptionUnitWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionBulkWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ReferenceID, + newSubscriptionGroupedTieredPackage: (x) => x.ReferenceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionUnitPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMatrixPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionThresholdTotalAmountPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedTieredPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredPackageWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionPackageWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionUnitWithPercentPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMatrixWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionUnitWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionBulkWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedWithProratedMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedWithMeteredMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMatrixWithDisplayNamePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMaxGroupTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionCumulativeGroupedBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMinimumCompositePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePricePercent value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnit(out var value)) { + /// // `value` is of type `NewSubscriptionUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnit([NotNullWhen(true)] out NewSubscriptionUnitPrice? value) + { + value = this.Value as NewSubscriptionUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTiered(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTiered( + [NotNullWhen(true)] out NewSubscriptionTieredPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulk(out var value)) { + /// // `value` is of type `NewSubscriptionBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulk([NotNullWhen(true)] out NewSubscriptionBulkPrice? value) + { + value = this.Value as NewSubscriptionBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackage(out var value)) { + /// // `value` is of type `NewSubscriptionPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackage( + [NotNullWhen(true)] out NewSubscriptionPackagePrice? value + ) + { + value = this.Value as NewSubscriptionPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrix(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrix( + [NotNullWhen(true)] out NewSubscriptionMatrixPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewSubscriptionThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionThresholdTotalAmount( + [NotNullWhen(true)] out NewSubscriptionThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewSubscriptionThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackage( + [NotNullWhen(true)] out NewSubscriptionTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTiered(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTiered( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackageWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackageWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackageWithAllocation( + [NotNullWhen(true)] out NewSubscriptionPackageWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithPercent(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithPercent( + [NotNullWhen(true)] out NewSubscriptionUnitWithPercentPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithAllocation( + [NotNullWhen(true)] out NewSubscriptionMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithProration( + [NotNullWhen(true)] out NewSubscriptionUnitWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedAllocation( + [NotNullWhen(true)] out NewSubscriptionGroupedAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulkWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulkWithProration( + [NotNullWhen(true)] out NewSubscriptionBulkWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds? value + ) + { + value = + this.Value + as SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithDisplayName( + [NotNullWhen(true)] out NewSubscriptionMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTieredPackage( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMaxGroupTieredPackage( + [NotNullWhen(true)] out NewSubscriptionMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewSubscriptionCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionCumulativeGroupedBulk( + [NotNullWhen(true)] out NewSubscriptionCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewSubscriptionCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation? value + ) + { + value = + this.Value + as SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMinimumComposite(out var value)) { + /// // `value` is of type `NewSubscriptionMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMinimumComposite( + [NotNullWhen(true)] out NewSubscriptionMinimumCompositePrice? value + ) + { + value = this.Value as NewSubscriptionMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsAddPricePricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent( + [NotNullWhen(true)] out SubscriptionSchedulePlanChangeParamsAddPricePricePercent? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsAddPricePricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] out SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePricePercent value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newSubscriptionUnit, + System::Action newSubscriptionTiered, + System::Action newSubscriptionBulk, + System::Action bulkWithFilters, + System::Action newSubscriptionPackage, + System::Action newSubscriptionMatrix, + System::Action newSubscriptionThresholdTotalAmount, + System::Action newSubscriptionTieredPackage, + System::Action newSubscriptionTieredWithMinimum, + System::Action newSubscriptionGroupedTiered, + System::Action newSubscriptionTieredPackageWithMinimum, + System::Action newSubscriptionPackageWithAllocation, + System::Action newSubscriptionUnitWithPercent, + System::Action newSubscriptionMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newSubscriptionUnitWithProration, + System::Action newSubscriptionGroupedAllocation, + System::Action newSubscriptionBulkWithProration, + System::Action newSubscriptionGroupedWithProratedMinimum, + System::Action newSubscriptionGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newSubscriptionMatrixWithDisplayName, + System::Action newSubscriptionGroupedTieredPackage, + System::Action newSubscriptionMaxGroupTieredPackage, + System::Action newSubscriptionScalableMatrixWithUnitPricing, + System::Action newSubscriptionScalableMatrixWithTieredPricing, + System::Action newSubscriptionCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newSubscriptionMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewSubscriptionUnitPrice value: + newSubscriptionUnit(value); + break; + case NewSubscriptionTieredPrice value: + newSubscriptionTiered(value); + break; + case NewSubscriptionBulkPrice value: + newSubscriptionBulk(value); + break; + case SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewSubscriptionPackagePrice value: + newSubscriptionPackage(value); + break; + case NewSubscriptionMatrixPrice value: + newSubscriptionMatrix(value); + break; + case NewSubscriptionThresholdTotalAmountPrice value: + newSubscriptionThresholdTotalAmount(value); + break; + case NewSubscriptionTieredPackagePrice value: + newSubscriptionTieredPackage(value); + break; + case NewSubscriptionTieredWithMinimumPrice value: + newSubscriptionTieredWithMinimum(value); + break; + case NewSubscriptionGroupedTieredPrice value: + newSubscriptionGroupedTiered(value); + break; + case NewSubscriptionTieredPackageWithMinimumPrice value: + newSubscriptionTieredPackageWithMinimum(value); + break; + case NewSubscriptionPackageWithAllocationPrice value: + newSubscriptionPackageWithAllocation(value); + break; + case NewSubscriptionUnitWithPercentPrice value: + newSubscriptionUnitWithPercent(value); + break; + case NewSubscriptionMatrixWithAllocationPrice value: + newSubscriptionMatrixWithAllocation(value); + break; + case SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration value: + tieredWithProration(value); + break; + case NewSubscriptionUnitWithProrationPrice value: + newSubscriptionUnitWithProration(value); + break; + case NewSubscriptionGroupedAllocationPrice value: + newSubscriptionGroupedAllocation(value); + break; + case NewSubscriptionBulkWithProrationPrice value: + newSubscriptionBulkWithProration(value); + break; + case NewSubscriptionGroupedWithProratedMinimumPrice value: + newSubscriptionGroupedWithProratedMinimum(value); + break; + case NewSubscriptionGroupedWithMeteredMinimumPrice value: + newSubscriptionGroupedWithMeteredMinimum(value); + break; + case SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewSubscriptionMatrixWithDisplayNamePrice value: + newSubscriptionMatrixWithDisplayName(value); + break; + case NewSubscriptionGroupedTieredPackagePrice value: + newSubscriptionGroupedTieredPackage(value); + break; + case NewSubscriptionMaxGroupTieredPackagePrice value: + newSubscriptionMaxGroupTieredPackage(value); + break; + case NewSubscriptionScalableMatrixWithUnitPricingPrice value: + newSubscriptionScalableMatrixWithUnitPricing(value); + break; + case NewSubscriptionScalableMatrixWithTieredPricingPrice value: + newSubscriptionScalableMatrixWithTieredPricing(value); + break; + case NewSubscriptionCumulativeGroupedBulkPrice value: + newSubscriptionCumulativeGroupedBulk(value); + break; + case SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewSubscriptionMinimumCompositePrice value: + newSubscriptionMinimumComposite(value); + break; + case SubscriptionSchedulePlanChangeParamsAddPricePricePercent value: + percent(value); + break; + case SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePrice" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePricePercent value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newSubscriptionUnit, + System::Func newSubscriptionTiered, + System::Func newSubscriptionBulk, + System::Func< + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters, + T + > bulkWithFilters, + System::Func newSubscriptionPackage, + System::Func newSubscriptionMatrix, + System::Func< + NewSubscriptionThresholdTotalAmountPrice, + T + > newSubscriptionThresholdTotalAmount, + System::Func newSubscriptionTieredPackage, + System::Func newSubscriptionTieredWithMinimum, + System::Func newSubscriptionGroupedTiered, + System::Func< + NewSubscriptionTieredPackageWithMinimumPrice, + T + > newSubscriptionTieredPackageWithMinimum, + System::Func< + NewSubscriptionPackageWithAllocationPrice, + T + > newSubscriptionPackageWithAllocation, + System::Func newSubscriptionUnitWithPercent, + System::Func< + NewSubscriptionMatrixWithAllocationPrice, + T + > newSubscriptionMatrixWithAllocation, + System::Func< + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration, + T + > tieredWithProration, + System::Func newSubscriptionUnitWithProration, + System::Func newSubscriptionGroupedAllocation, + System::Func newSubscriptionBulkWithProration, + System::Func< + NewSubscriptionGroupedWithProratedMinimumPrice, + T + > newSubscriptionGroupedWithProratedMinimum, + System::Func< + NewSubscriptionGroupedWithMeteredMinimumPrice, + T + > newSubscriptionGroupedWithMeteredMinimum, + System::Func< + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func< + NewSubscriptionMatrixWithDisplayNamePrice, + T + > newSubscriptionMatrixWithDisplayName, + System::Func< + NewSubscriptionGroupedTieredPackagePrice, + T + > newSubscriptionGroupedTieredPackage, + System::Func< + NewSubscriptionMaxGroupTieredPackagePrice, + T + > newSubscriptionMaxGroupTieredPackage, + System::Func< + NewSubscriptionScalableMatrixWithUnitPricingPrice, + T + > newSubscriptionScalableMatrixWithUnitPricing, + System::Func< + NewSubscriptionScalableMatrixWithTieredPricingPrice, + T + > newSubscriptionScalableMatrixWithTieredPricing, + System::Func< + NewSubscriptionCumulativeGroupedBulkPrice, + T + > newSubscriptionCumulativeGroupedBulk, + System::Func< + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newSubscriptionMinimumComposite, + System::Func percent, + System::Func eventOutput + ) + { + return this.Value switch + { + NewSubscriptionUnitPrice value => newSubscriptionUnit(value), + NewSubscriptionTieredPrice value => newSubscriptionTiered(value), + NewSubscriptionBulkPrice value => newSubscriptionBulk(value), + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters value => + bulkWithFilters(value), + NewSubscriptionPackagePrice value => newSubscriptionPackage(value), + NewSubscriptionMatrixPrice value => newSubscriptionMatrix(value), + NewSubscriptionThresholdTotalAmountPrice value => newSubscriptionThresholdTotalAmount( + value + ), + NewSubscriptionTieredPackagePrice value => newSubscriptionTieredPackage(value), + NewSubscriptionTieredWithMinimumPrice value => newSubscriptionTieredWithMinimum(value), + NewSubscriptionGroupedTieredPrice value => newSubscriptionGroupedTiered(value), + NewSubscriptionTieredPackageWithMinimumPrice value => + newSubscriptionTieredPackageWithMinimum(value), + NewSubscriptionPackageWithAllocationPrice value => newSubscriptionPackageWithAllocation( + value + ), + NewSubscriptionUnitWithPercentPrice value => newSubscriptionUnitWithPercent(value), + NewSubscriptionMatrixWithAllocationPrice value => newSubscriptionMatrixWithAllocation( + value + ), + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration value => + tieredWithProration(value), + NewSubscriptionUnitWithProrationPrice value => newSubscriptionUnitWithProration(value), + NewSubscriptionGroupedAllocationPrice value => newSubscriptionGroupedAllocation(value), + NewSubscriptionBulkWithProrationPrice value => newSubscriptionBulkWithProration(value), + NewSubscriptionGroupedWithProratedMinimumPrice value => + newSubscriptionGroupedWithProratedMinimum(value), + NewSubscriptionGroupedWithMeteredMinimumPrice value => + newSubscriptionGroupedWithMeteredMinimum(value), + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewSubscriptionMatrixWithDisplayNamePrice value => newSubscriptionMatrixWithDisplayName( + value + ), + NewSubscriptionGroupedTieredPackagePrice value => newSubscriptionGroupedTieredPackage( + value + ), + NewSubscriptionMaxGroupTieredPackagePrice value => newSubscriptionMaxGroupTieredPackage( + value + ), + NewSubscriptionScalableMatrixWithUnitPricingPrice value => + newSubscriptionScalableMatrixWithUnitPricing(value), + NewSubscriptionScalableMatrixWithTieredPricingPrice value => + newSubscriptionScalableMatrixWithTieredPricing(value), + NewSubscriptionCumulativeGroupedBulkPrice value => newSubscriptionCumulativeGroupedBulk( + value + ), + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewSubscriptionMinimumCompositePrice value => newSubscriptionMinimumComposite(value), + SubscriptionSchedulePlanChangeParamsAddPricePricePercent value => percent(value), + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput value => eventOutput( + value + ), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePrice" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionUnitPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionBulkPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMatrixPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedTieredPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionUnitWithPercentPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionUnitWithProrationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedAllocationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionBulkWithProrationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + NewSubscriptionMinimumCompositePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePricePercent value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePrice( + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePrice" + ); + } + this.Switch( + (newSubscriptionUnit) => newSubscriptionUnit.Validate(), + (newSubscriptionTiered) => newSubscriptionTiered.Validate(), + (newSubscriptionBulk) => newSubscriptionBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newSubscriptionPackage) => newSubscriptionPackage.Validate(), + (newSubscriptionMatrix) => newSubscriptionMatrix.Validate(), + (newSubscriptionThresholdTotalAmount) => newSubscriptionThresholdTotalAmount.Validate(), + (newSubscriptionTieredPackage) => newSubscriptionTieredPackage.Validate(), + (newSubscriptionTieredWithMinimum) => newSubscriptionTieredWithMinimum.Validate(), + (newSubscriptionGroupedTiered) => newSubscriptionGroupedTiered.Validate(), + (newSubscriptionTieredPackageWithMinimum) => + newSubscriptionTieredPackageWithMinimum.Validate(), + (newSubscriptionPackageWithAllocation) => + newSubscriptionPackageWithAllocation.Validate(), + (newSubscriptionUnitWithPercent) => newSubscriptionUnitWithPercent.Validate(), + (newSubscriptionMatrixWithAllocation) => newSubscriptionMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newSubscriptionUnitWithProration) => newSubscriptionUnitWithProration.Validate(), + (newSubscriptionGroupedAllocation) => newSubscriptionGroupedAllocation.Validate(), + (newSubscriptionBulkWithProration) => newSubscriptionBulkWithProration.Validate(), + (newSubscriptionGroupedWithProratedMinimum) => + newSubscriptionGroupedWithProratedMinimum.Validate(), + (newSubscriptionGroupedWithMeteredMinimum) => + newSubscriptionGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newSubscriptionMatrixWithDisplayName) => + newSubscriptionMatrixWithDisplayName.Validate(), + (newSubscriptionGroupedTieredPackage) => newSubscriptionGroupedTieredPackage.Validate(), + (newSubscriptionMaxGroupTieredPackage) => + newSubscriptionMaxGroupTieredPackage.Validate(), + (newSubscriptionScalableMatrixWithUnitPricing) => + newSubscriptionScalableMatrixWithUnitPricing.Validate(), + (newSubscriptionScalableMatrixWithTieredPricing) => + newSubscriptionScalableMatrixWithTieredPricing.Validate(), + (newSubscriptionCumulativeGroupedBulk) => + newSubscriptionCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newSubscriptionMinimumComposite) => newSubscriptionMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(SubscriptionSchedulePlanChangeParamsAddPricePrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFilters.FromRawUnchecked(rawData); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier( + string unitAmount + ) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration( + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration subscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProration.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig( + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig subscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier( + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier subscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationTieredWithProrationConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceTieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds, + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds( + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds subscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholds.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Custom, + _ => + (SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig subscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation, + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation( + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation subscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocation.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Custom, + _ => + (SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() + { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig subscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base( + subscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePricePercent, + SubscriptionSchedulePlanChangeParamsAddPricePricePercentFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercent( + SubscriptionSchedulePlanChangeParamsAddPricePricePercent subscriptionSchedulePlanChangeParamsAddPricePricePercent + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePricePercent) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercent( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePricePercent( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePricePercentFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsAddPricePricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter(typeof(SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadenceConverter))] +public enum SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.SemiAnnual, + "monthly" => SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Quarterly, + "one_time" => SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.OneTime, + "custom" => SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Annual => "annual", + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsAddPricePricePercentCadence.Custom => "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig, + SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig + : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig() { } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig( + SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig subscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePricePercentPercentConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput, + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput( + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput subscriptionSchedulePlanChangeParamsAddPricePriceEventOutput + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePriceEventOutput) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.OneTime, + "custom" => SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig, + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig() { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig( + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig subscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig + ) + : base(subscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig) { } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig( + string unitRatingKey + ) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputEventOutputConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsAddPricePriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +/// +/// Reset billing periods to be aligned with the plan change's effective date or start +/// of the month. Defaults to `unchanged` which keeps subscription's existing billing +/// cycle alignment. +/// +[JsonConverter(typeof(BillingCycleAlignmentConverter))] +public enum BillingCycleAlignment +{ + Unchanged, + PlanChangeDate, + StartOfMonth, +} + +sealed class BillingCycleAlignmentConverter : JsonConverter +{ + public override BillingCycleAlignment Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "unchanged" => BillingCycleAlignment.Unchanged, + "plan_change_date" => BillingCycleAlignment.PlanChangeDate, + "start_of_month" => BillingCycleAlignment.StartOfMonth, + _ => (BillingCycleAlignment)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + BillingCycleAlignment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + BillingCycleAlignment.Unchanged => "unchanged", + BillingCycleAlignment.PlanChangeDate => "plan_change_date", + BillingCycleAlignment.StartOfMonth => "start_of_month", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsRemoveAdjustment, + SubscriptionSchedulePlanChangeParamsRemoveAdjustmentFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsRemoveAdjustment : JsonModel +{ + /// + /// The id of the adjustment to remove on the subscription. + /// + public required string AdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "adjustment_id"); } + init { JsonModel.Set(this._rawData, "adjustment_id", value); } + } + + /// + public override void Validate() + { + _ = this.AdjustmentID; + } + + public SubscriptionSchedulePlanChangeParamsRemoveAdjustment() { } + + public SubscriptionSchedulePlanChangeParamsRemoveAdjustment( + SubscriptionSchedulePlanChangeParamsRemoveAdjustment subscriptionSchedulePlanChangeParamsRemoveAdjustment + ) + : base(subscriptionSchedulePlanChangeParamsRemoveAdjustment) { } + + public SubscriptionSchedulePlanChangeParamsRemoveAdjustment( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsRemoveAdjustment( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsRemoveAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsRemoveAdjustment(string adjustmentID) + : this() + { + this.AdjustmentID = adjustmentID; + } +} + +class SubscriptionSchedulePlanChangeParamsRemoveAdjustmentFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsRemoveAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsRemoveAdjustment.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsRemovePrice, + SubscriptionSchedulePlanChangeParamsRemovePriceFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsRemovePrice : JsonModel +{ + /// + /// The external price id of the price to remove on the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// The id of the price to remove on the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.ExternalPriceID; + _ = this.PriceID; + } + + public SubscriptionSchedulePlanChangeParamsRemovePrice() { } + + public SubscriptionSchedulePlanChangeParamsRemovePrice( + SubscriptionSchedulePlanChangeParamsRemovePrice subscriptionSchedulePlanChangeParamsRemovePrice + ) + : base(subscriptionSchedulePlanChangeParamsRemovePrice) { } + + public SubscriptionSchedulePlanChangeParamsRemovePrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsRemovePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsRemovePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsRemovePriceFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsRemovePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsRemovePrice.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplaceAdjustment, + SubscriptionSchedulePlanChangeParamsReplaceAdjustmentFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplaceAdjustment : JsonModel +{ + /// + /// The definition of a new adjustment to create and add to the subscription. + /// + public required SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment Adjustment + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "adjustment" + ); + } + init { JsonModel.Set(this._rawData, "adjustment", value); } + } + + /// + /// The id of the adjustment on the plan to replace in the subscription. + /// + public required string ReplacesAdjustmentID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_adjustment_id"); } + init { JsonModel.Set(this._rawData, "replaces_adjustment_id", value); } + } + + /// + public override void Validate() + { + this.Adjustment.Validate(); + _ = this.ReplacesAdjustmentID; + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustment() { } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustment( + SubscriptionSchedulePlanChangeParamsReplaceAdjustment subscriptionSchedulePlanChangeParamsReplaceAdjustment + ) + : base(subscriptionSchedulePlanChangeParamsReplaceAdjustment) { } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustment( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplaceAdjustment( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplaceAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplaceAdjustmentFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplaceAdjustment FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsReplaceAdjustment.FromRawUnchecked(rawData); +} + +/// +/// The definition of a new adjustment to create and add to the subscription. +/// +[JsonConverter(typeof(SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustmentConverter))] +public record class SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string? Currency + { + get + { + return Match( + newPercentageDiscount: (x) => x.Currency, + newUsageDiscount: (x) => x.Currency, + newAmountDiscount: (x) => x.Currency, + newMinimum: (x) => x.Currency, + newMaximum: (x) => x.Currency + ); + } + } + + public bool? IsInvoiceLevel + { + get + { + return Match( + newPercentageDiscount: (x) => x.IsInvoiceLevel, + newUsageDiscount: (x) => x.IsInvoiceLevel, + newAmountDiscount: (x) => x.IsInvoiceLevel, + newMinimum: (x) => x.IsInvoiceLevel, + newMaximum: (x) => x.IsInvoiceLevel + ); + } + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewPercentageDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewUsageDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewAmountDiscount value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewMinimum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewMaximum value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewPercentageDiscount(out var value)) { + /// // `value` is of type `NewPercentageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewPercentageDiscount([NotNullWhen(true)] out NewPercentageDiscount? value) + { + value = this.Value as NewPercentageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewUsageDiscount(out var value)) { + /// // `value` is of type `NewUsageDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewUsageDiscount([NotNullWhen(true)] out NewUsageDiscount? value) + { + value = this.Value as NewUsageDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewAmountDiscount(out var value)) { + /// // `value` is of type `NewAmountDiscount` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewAmountDiscount([NotNullWhen(true)] out NewAmountDiscount? value) + { + value = this.Value as NewAmountDiscount; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMinimum(out var value)) { + /// // `value` is of type `NewMinimum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMinimum([NotNullWhen(true)] out NewMinimum? value) + { + value = this.Value as NewMinimum; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewMaximum(out var value)) { + /// // `value` is of type `NewMaximum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewMaximum([NotNullWhen(true)] out NewMaximum? value) + { + value = this.Value as NewMaximum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newPercentageDiscount, + System::Action newUsageDiscount, + System::Action newAmountDiscount, + System::Action newMinimum, + System::Action newMaximum + ) + { + switch (this.Value) + { + case NewPercentageDiscount value: + newPercentageDiscount(value); + break; + case NewUsageDiscount value: + newUsageDiscount(value); + break; + case NewAmountDiscount value: + newAmountDiscount(value); + break; + case NewMinimum value: + newMinimum(value); + break; + case NewMaximum value: + newMaximum(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewPercentageDiscount value) => {...}, + /// (NewUsageDiscount value) => {...}, + /// (NewAmountDiscount value) => {...}, + /// (NewMinimum value) => {...}, + /// (NewMaximum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newPercentageDiscount, + System::Func newUsageDiscount, + System::Func newAmountDiscount, + System::Func newMinimum, + System::Func newMaximum + ) + { + return this.Value switch + { + NewPercentageDiscount value => newPercentageDiscount(value), + NewUsageDiscount value => newUsageDiscount(value), + NewAmountDiscount value => newAmountDiscount(value), + NewMinimum value => newMinimum(value), + NewMaximum value => newMaximum(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewPercentageDiscount value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewUsageDiscount value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewAmountDiscount value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewMinimum value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment( + NewMaximum value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment" + ); + } + this.Switch( + (newPercentageDiscount) => newPercentageDiscount.Validate(), + (newUsageDiscount) => newUsageDiscount.Validate(), + (newAmountDiscount) => newAmountDiscount.Validate(), + (newMinimum) => newMinimum.Validate(), + (newMaximum) => newMaximum.Validate() + ); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustmentConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? adjustmentType; + try + { + adjustmentType = element.GetProperty("adjustment_type").GetString(); + } + catch + { + adjustmentType = null; + } + + switch (adjustmentType) + { + case "percentage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "usage_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "amount_discount": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "maximum": + { + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplaceAdjustmentAdjustment value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePrice, + SubscriptionSchedulePlanChangeParamsReplacePriceFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePrice : JsonModel +{ + /// + /// The id of the price on the plan to replace in the subscription. + /// + public required string ReplacesPriceID + { + get { return JsonModel.GetNotNullClass(this.RawData, "replaces_price_id"); } + init { JsonModel.Set(this._rawData, "replaces_price_id", value); } + } + + /// + /// The definition of a new allocation price to create and add to the subscription. + /// + public NewAllocationPrice? AllocationPrice + { + get + { + return JsonModel.GetNullableClass(this.RawData, "allocation_price"); + } + init { JsonModel.Set(this._rawData, "allocation_price", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for + /// the replacement price. + /// + [System::Obsolete("deprecated")] + public IReadOnlyList? Discounts + { + get + { + return JsonModel.GetNullableClass>(this.RawData, "discounts"); + } + init { JsonModel.Set(this._rawData, "discounts", value); } + } + + /// + /// The external price id of the price to add to the subscription. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// The new quantity of the price, if the price is a fixed price. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount + /// for the replacement price. + /// + [System::Obsolete("deprecated")] + public string? MaximumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "maximum_amount"); } + init { JsonModel.Set(this._rawData, "maximum_amount", value); } + } + + /// + /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount + /// for the replacement price. + /// + [System::Obsolete("deprecated")] + public string? MinimumAmount + { + get { return JsonModel.GetNullableClass(this.RawData, "minimum_amount"); } + init { JsonModel.Set(this._rawData, "minimum_amount", value); } + } + + /// + /// New subscription price request body params. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePrice? Price + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "price" + ); + } + init { JsonModel.Set(this._rawData, "price", value); } + } + + /// + /// The id of the price to add to the subscription. + /// + public string? PriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "price_id"); } + init { JsonModel.Set(this._rawData, "price_id", value); } + } + + /// + public override void Validate() + { + _ = this.ReplacesPriceID; + this.AllocationPrice?.Validate(); + foreach (var item in this.Discounts ?? []) + { + item.Validate(); + } + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.MaximumAmount; + _ = this.MinimumAmount; + this.Price?.Validate(); + _ = this.PriceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePrice() { } + + public SubscriptionSchedulePlanChangeParamsReplacePrice( + SubscriptionSchedulePlanChangeParamsReplacePrice subscriptionSchedulePlanChangeParamsReplacePrice + ) + : base(subscriptionSchedulePlanChangeParamsReplacePrice) { } + + public SubscriptionSchedulePlanChangeParamsReplacePrice( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePrice(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsReplacePrice(string replacesPriceID) + : this() + { + this.ReplacesPriceID = replacesPriceID; + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePriceFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePrice FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsReplacePrice.FromRawUnchecked(rawData); +} + +/// +/// New subscription price request body params. +/// +[JsonConverter(typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceConverter))] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePrice +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public string ItemID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ItemID, + newSubscriptionTiered: (x) => x.ItemID, + newSubscriptionBulk: (x) => x.ItemID, + bulkWithFilters: (x) => x.ItemID, + newSubscriptionPackage: (x) => x.ItemID, + newSubscriptionMatrix: (x) => x.ItemID, + newSubscriptionThresholdTotalAmount: (x) => x.ItemID, + newSubscriptionTieredPackage: (x) => x.ItemID, + newSubscriptionTieredWithMinimum: (x) => x.ItemID, + newSubscriptionGroupedTiered: (x) => x.ItemID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ItemID, + newSubscriptionPackageWithAllocation: (x) => x.ItemID, + newSubscriptionUnitWithPercent: (x) => x.ItemID, + newSubscriptionMatrixWithAllocation: (x) => x.ItemID, + tieredWithProration: (x) => x.ItemID, + newSubscriptionUnitWithProration: (x) => x.ItemID, + newSubscriptionGroupedAllocation: (x) => x.ItemID, + newSubscriptionBulkWithProration: (x) => x.ItemID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ItemID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ItemID, + groupedWithMinMaxThresholds: (x) => x.ItemID, + newSubscriptionMatrixWithDisplayName: (x) => x.ItemID, + newSubscriptionGroupedTieredPackage: (x) => x.ItemID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ItemID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ItemID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ItemID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ItemID, + cumulativeGroupedAllocation: (x) => x.ItemID, + newSubscriptionMinimumComposite: (x) => x.ItemID, + percent: (x) => x.ItemID, + eventOutput: (x) => x.ItemID + ); + } + } + + public string Name + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Name, + newSubscriptionTiered: (x) => x.Name, + newSubscriptionBulk: (x) => x.Name, + bulkWithFilters: (x) => x.Name, + newSubscriptionPackage: (x) => x.Name, + newSubscriptionMatrix: (x) => x.Name, + newSubscriptionThresholdTotalAmount: (x) => x.Name, + newSubscriptionTieredPackage: (x) => x.Name, + newSubscriptionTieredWithMinimum: (x) => x.Name, + newSubscriptionGroupedTiered: (x) => x.Name, + newSubscriptionTieredPackageWithMinimum: (x) => x.Name, + newSubscriptionPackageWithAllocation: (x) => x.Name, + newSubscriptionUnitWithPercent: (x) => x.Name, + newSubscriptionMatrixWithAllocation: (x) => x.Name, + tieredWithProration: (x) => x.Name, + newSubscriptionUnitWithProration: (x) => x.Name, + newSubscriptionGroupedAllocation: (x) => x.Name, + newSubscriptionBulkWithProration: (x) => x.Name, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Name, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Name, + groupedWithMinMaxThresholds: (x) => x.Name, + newSubscriptionMatrixWithDisplayName: (x) => x.Name, + newSubscriptionGroupedTieredPackage: (x) => x.Name, + newSubscriptionMaxGroupTieredPackage: (x) => x.Name, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Name, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Name, + newSubscriptionCumulativeGroupedBulk: (x) => x.Name, + cumulativeGroupedAllocation: (x) => x.Name, + newSubscriptionMinimumComposite: (x) => x.Name, + percent: (x) => x.Name, + eventOutput: (x) => x.Name + ); + } + } + + public string? BillableMetricID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillableMetricID, + newSubscriptionTiered: (x) => x.BillableMetricID, + newSubscriptionBulk: (x) => x.BillableMetricID, + bulkWithFilters: (x) => x.BillableMetricID, + newSubscriptionPackage: (x) => x.BillableMetricID, + newSubscriptionMatrix: (x) => x.BillableMetricID, + newSubscriptionThresholdTotalAmount: (x) => x.BillableMetricID, + newSubscriptionTieredPackage: (x) => x.BillableMetricID, + newSubscriptionTieredWithMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedTiered: (x) => x.BillableMetricID, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillableMetricID, + newSubscriptionPackageWithAllocation: (x) => x.BillableMetricID, + newSubscriptionUnitWithPercent: (x) => x.BillableMetricID, + newSubscriptionMatrixWithAllocation: (x) => x.BillableMetricID, + tieredWithProration: (x) => x.BillableMetricID, + newSubscriptionUnitWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionBulkWithProration: (x) => x.BillableMetricID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillableMetricID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillableMetricID, + groupedWithMinMaxThresholds: (x) => x.BillableMetricID, + newSubscriptionMatrixWithDisplayName: (x) => x.BillableMetricID, + newSubscriptionGroupedTieredPackage: (x) => x.BillableMetricID, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillableMetricID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillableMetricID, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillableMetricID, + cumulativeGroupedAllocation: (x) => x.BillableMetricID, + newSubscriptionMinimumComposite: (x) => x.BillableMetricID, + percent: (x) => x.BillableMetricID, + eventOutput: (x) => x.BillableMetricID + ); + } + } + + public bool? BilledInAdvance + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BilledInAdvance, + newSubscriptionTiered: (x) => x.BilledInAdvance, + newSubscriptionBulk: (x) => x.BilledInAdvance, + bulkWithFilters: (x) => x.BilledInAdvance, + newSubscriptionPackage: (x) => x.BilledInAdvance, + newSubscriptionMatrix: (x) => x.BilledInAdvance, + newSubscriptionThresholdTotalAmount: (x) => x.BilledInAdvance, + newSubscriptionTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionTieredWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedTiered: (x) => x.BilledInAdvance, + newSubscriptionTieredPackageWithMinimum: (x) => x.BilledInAdvance, + newSubscriptionPackageWithAllocation: (x) => x.BilledInAdvance, + newSubscriptionUnitWithPercent: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithAllocation: (x) => x.BilledInAdvance, + tieredWithProration: (x) => x.BilledInAdvance, + newSubscriptionUnitWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionBulkWithProration: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BilledInAdvance, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BilledInAdvance, + groupedWithMinMaxThresholds: (x) => x.BilledInAdvance, + newSubscriptionMatrixWithDisplayName: (x) => x.BilledInAdvance, + newSubscriptionGroupedTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionMaxGroupTieredPackage: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BilledInAdvance, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BilledInAdvance, + newSubscriptionCumulativeGroupedBulk: (x) => x.BilledInAdvance, + cumulativeGroupedAllocation: (x) => x.BilledInAdvance, + newSubscriptionMinimumComposite: (x) => x.BilledInAdvance, + percent: (x) => x.BilledInAdvance, + eventOutput: (x) => x.BilledInAdvance + ); + } + } + + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.BillingCycleConfiguration, + newSubscriptionTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionBulk: (x) => x.BillingCycleConfiguration, + bulkWithFilters: (x) => x.BillingCycleConfiguration, + newSubscriptionPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrix: (x) => x.BillingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.BillingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.BillingCycleConfiguration, + tieredWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.BillingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.BillingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.BillingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.BillingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.BillingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.BillingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.BillingCycleConfiguration, + percent: (x) => x.BillingCycleConfiguration, + eventOutput: (x) => x.BillingCycleConfiguration + ); + } + } + + public double? ConversionRate + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ConversionRate, + newSubscriptionTiered: (x) => x.ConversionRate, + newSubscriptionBulk: (x) => x.ConversionRate, + bulkWithFilters: (x) => x.ConversionRate, + newSubscriptionPackage: (x) => x.ConversionRate, + newSubscriptionMatrix: (x) => x.ConversionRate, + newSubscriptionThresholdTotalAmount: (x) => x.ConversionRate, + newSubscriptionTieredPackage: (x) => x.ConversionRate, + newSubscriptionTieredWithMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedTiered: (x) => x.ConversionRate, + newSubscriptionTieredPackageWithMinimum: (x) => x.ConversionRate, + newSubscriptionPackageWithAllocation: (x) => x.ConversionRate, + newSubscriptionUnitWithPercent: (x) => x.ConversionRate, + newSubscriptionMatrixWithAllocation: (x) => x.ConversionRate, + tieredWithProration: (x) => x.ConversionRate, + newSubscriptionUnitWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionBulkWithProration: (x) => x.ConversionRate, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ConversionRate, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ConversionRate, + groupedWithMinMaxThresholds: (x) => x.ConversionRate, + newSubscriptionMatrixWithDisplayName: (x) => x.ConversionRate, + newSubscriptionGroupedTieredPackage: (x) => x.ConversionRate, + newSubscriptionMaxGroupTieredPackage: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ConversionRate, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ConversionRate, + newSubscriptionCumulativeGroupedBulk: (x) => x.ConversionRate, + cumulativeGroupedAllocation: (x) => x.ConversionRate, + newSubscriptionMinimumComposite: (x) => x.ConversionRate, + percent: (x) => x.ConversionRate, + eventOutput: (x) => x.ConversionRate + ); + } + } + + public string? Currency + { + get + { + return Match( + newSubscriptionUnit: (x) => x.Currency, + newSubscriptionTiered: (x) => x.Currency, + newSubscriptionBulk: (x) => x.Currency, + bulkWithFilters: (x) => x.Currency, + newSubscriptionPackage: (x) => x.Currency, + newSubscriptionMatrix: (x) => x.Currency, + newSubscriptionThresholdTotalAmount: (x) => x.Currency, + newSubscriptionTieredPackage: (x) => x.Currency, + newSubscriptionTieredWithMinimum: (x) => x.Currency, + newSubscriptionGroupedTiered: (x) => x.Currency, + newSubscriptionTieredPackageWithMinimum: (x) => x.Currency, + newSubscriptionPackageWithAllocation: (x) => x.Currency, + newSubscriptionUnitWithPercent: (x) => x.Currency, + newSubscriptionMatrixWithAllocation: (x) => x.Currency, + tieredWithProration: (x) => x.Currency, + newSubscriptionUnitWithProration: (x) => x.Currency, + newSubscriptionGroupedAllocation: (x) => x.Currency, + newSubscriptionBulkWithProration: (x) => x.Currency, + newSubscriptionGroupedWithProratedMinimum: (x) => x.Currency, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.Currency, + groupedWithMinMaxThresholds: (x) => x.Currency, + newSubscriptionMatrixWithDisplayName: (x) => x.Currency, + newSubscriptionGroupedTieredPackage: (x) => x.Currency, + newSubscriptionMaxGroupTieredPackage: (x) => x.Currency, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.Currency, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.Currency, + newSubscriptionCumulativeGroupedBulk: (x) => x.Currency, + cumulativeGroupedAllocation: (x) => x.Currency, + newSubscriptionMinimumComposite: (x) => x.Currency, + percent: (x) => x.Currency, + eventOutput: (x) => x.Currency + ); + } + } + + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulk: (x) => x.DimensionalPriceConfiguration, + bulkWithFilters: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrix: (x) => x.DimensionalPriceConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTiered: (x) => x.DimensionalPriceConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithPercent: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.DimensionalPriceConfiguration, + tieredWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionUnitWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionBulkWithProration: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.DimensionalPriceConfiguration, + groupedWithMinMaxThresholds: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.DimensionalPriceConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.DimensionalPriceConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.DimensionalPriceConfiguration, + cumulativeGroupedAllocation: (x) => x.DimensionalPriceConfiguration, + newSubscriptionMinimumComposite: (x) => x.DimensionalPriceConfiguration, + percent: (x) => x.DimensionalPriceConfiguration, + eventOutput: (x) => x.DimensionalPriceConfiguration + ); + } + } + + public string? ExternalPriceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ExternalPriceID, + newSubscriptionTiered: (x) => x.ExternalPriceID, + newSubscriptionBulk: (x) => x.ExternalPriceID, + bulkWithFilters: (x) => x.ExternalPriceID, + newSubscriptionPackage: (x) => x.ExternalPriceID, + newSubscriptionMatrix: (x) => x.ExternalPriceID, + newSubscriptionThresholdTotalAmount: (x) => x.ExternalPriceID, + newSubscriptionTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionTieredWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedTiered: (x) => x.ExternalPriceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ExternalPriceID, + newSubscriptionPackageWithAllocation: (x) => x.ExternalPriceID, + newSubscriptionUnitWithPercent: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithAllocation: (x) => x.ExternalPriceID, + tieredWithProration: (x) => x.ExternalPriceID, + newSubscriptionUnitWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionBulkWithProration: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ExternalPriceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ExternalPriceID, + groupedWithMinMaxThresholds: (x) => x.ExternalPriceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ExternalPriceID, + newSubscriptionGroupedTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ExternalPriceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ExternalPriceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ExternalPriceID, + cumulativeGroupedAllocation: (x) => x.ExternalPriceID, + newSubscriptionMinimumComposite: (x) => x.ExternalPriceID, + percent: (x) => x.ExternalPriceID, + eventOutput: (x) => x.ExternalPriceID + ); + } + } + + public double? FixedPriceQuantity + { + get + { + return Match( + newSubscriptionUnit: (x) => x.FixedPriceQuantity, + newSubscriptionTiered: (x) => x.FixedPriceQuantity, + newSubscriptionBulk: (x) => x.FixedPriceQuantity, + bulkWithFilters: (x) => x.FixedPriceQuantity, + newSubscriptionPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMatrix: (x) => x.FixedPriceQuantity, + newSubscriptionThresholdTotalAmount: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionTieredWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTiered: (x) => x.FixedPriceQuantity, + newSubscriptionTieredPackageWithMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionPackageWithAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithPercent: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithAllocation: (x) => x.FixedPriceQuantity, + tieredWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionUnitWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionBulkWithProration: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithProratedMinimum: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.FixedPriceQuantity, + groupedWithMinMaxThresholds: (x) => x.FixedPriceQuantity, + newSubscriptionMatrixWithDisplayName: (x) => x.FixedPriceQuantity, + newSubscriptionGroupedTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionMaxGroupTieredPackage: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.FixedPriceQuantity, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.FixedPriceQuantity, + newSubscriptionCumulativeGroupedBulk: (x) => x.FixedPriceQuantity, + cumulativeGroupedAllocation: (x) => x.FixedPriceQuantity, + newSubscriptionMinimumComposite: (x) => x.FixedPriceQuantity, + percent: (x) => x.FixedPriceQuantity, + eventOutput: (x) => x.FixedPriceQuantity + ); + } + } + + public string? InvoiceGroupingKey + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoiceGroupingKey, + newSubscriptionTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionBulk: (x) => x.InvoiceGroupingKey, + bulkWithFilters: (x) => x.InvoiceGroupingKey, + newSubscriptionPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrix: (x) => x.InvoiceGroupingKey, + newSubscriptionThresholdTotalAmount: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTiered: (x) => x.InvoiceGroupingKey, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionPackageWithAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithPercent: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithAllocation: (x) => x.InvoiceGroupingKey, + tieredWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionUnitWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionBulkWithProration: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoiceGroupingKey, + groupedWithMinMaxThresholds: (x) => x.InvoiceGroupingKey, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoiceGroupingKey, + newSubscriptionGroupedTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.InvoiceGroupingKey, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoiceGroupingKey, + cumulativeGroupedAllocation: (x) => x.InvoiceGroupingKey, + newSubscriptionMinimumComposite: (x) => x.InvoiceGroupingKey, + percent: (x) => x.InvoiceGroupingKey, + eventOutput: (x) => x.InvoiceGroupingKey + ); + } + } + + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return Match( + newSubscriptionUnit: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulk: (x) => x.InvoicingCycleConfiguration, + bulkWithFilters: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrix: (x) => x.InvoicingCycleConfiguration, + newSubscriptionThresholdTotalAmount: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTiered: (x) => x.InvoicingCycleConfiguration, + newSubscriptionTieredPackageWithMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionPackageWithAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithPercent: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithAllocation: (x) => x.InvoicingCycleConfiguration, + tieredWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionUnitWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionBulkWithProration: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithProratedMinimum: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.InvoicingCycleConfiguration, + groupedWithMinMaxThresholds: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMatrixWithDisplayName: (x) => x.InvoicingCycleConfiguration, + newSubscriptionGroupedTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMaxGroupTieredPackage: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.InvoicingCycleConfiguration, + newSubscriptionScalableMatrixWithTieredPricing: (x) => + x.InvoicingCycleConfiguration, + newSubscriptionCumulativeGroupedBulk: (x) => x.InvoicingCycleConfiguration, + cumulativeGroupedAllocation: (x) => x.InvoicingCycleConfiguration, + newSubscriptionMinimumComposite: (x) => x.InvoicingCycleConfiguration, + percent: (x) => x.InvoicingCycleConfiguration, + eventOutput: (x) => x.InvoicingCycleConfiguration + ); + } + } + + public string? ReferenceID + { + get + { + return Match( + newSubscriptionUnit: (x) => x.ReferenceID, + newSubscriptionTiered: (x) => x.ReferenceID, + newSubscriptionBulk: (x) => x.ReferenceID, + bulkWithFilters: (x) => x.ReferenceID, + newSubscriptionPackage: (x) => x.ReferenceID, + newSubscriptionMatrix: (x) => x.ReferenceID, + newSubscriptionThresholdTotalAmount: (x) => x.ReferenceID, + newSubscriptionTieredPackage: (x) => x.ReferenceID, + newSubscriptionTieredWithMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedTiered: (x) => x.ReferenceID, + newSubscriptionTieredPackageWithMinimum: (x) => x.ReferenceID, + newSubscriptionPackageWithAllocation: (x) => x.ReferenceID, + newSubscriptionUnitWithPercent: (x) => x.ReferenceID, + newSubscriptionMatrixWithAllocation: (x) => x.ReferenceID, + tieredWithProration: (x) => x.ReferenceID, + newSubscriptionUnitWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionBulkWithProration: (x) => x.ReferenceID, + newSubscriptionGroupedWithProratedMinimum: (x) => x.ReferenceID, + newSubscriptionGroupedWithMeteredMinimum: (x) => x.ReferenceID, + groupedWithMinMaxThresholds: (x) => x.ReferenceID, + newSubscriptionMatrixWithDisplayName: (x) => x.ReferenceID, + newSubscriptionGroupedTieredPackage: (x) => x.ReferenceID, + newSubscriptionMaxGroupTieredPackage: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithUnitPricing: (x) => x.ReferenceID, + newSubscriptionScalableMatrixWithTieredPricing: (x) => x.ReferenceID, + newSubscriptionCumulativeGroupedBulk: (x) => x.ReferenceID, + cumulativeGroupedAllocation: (x) => x.ReferenceID, + newSubscriptionMinimumComposite: (x) => x.ReferenceID, + percent: (x) => x.ReferenceID, + eventOutput: (x) => x.ReferenceID + ); + } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionUnitPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMatrixPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionThresholdTotalAmountPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedTieredPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredPackageWithMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionPackageWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionUnitWithPercentPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMatrixWithAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionUnitWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedAllocationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionBulkWithProrationPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedWithProratedMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedWithMeteredMinimumPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMatrixWithDisplayNamePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMaxGroupTieredPackagePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionCumulativeGroupedBulkPrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMinimumCompositePrice value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePricePercent value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePrice(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnit(out var value)) { + /// // `value` is of type `NewSubscriptionUnitPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnit([NotNullWhen(true)] out NewSubscriptionUnitPrice? value) + { + value = this.Value as NewSubscriptionUnitPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTiered(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTiered( + [NotNullWhen(true)] out NewSubscriptionTieredPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulk(out var value)) { + /// // `value` is of type `NewSubscriptionBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulk([NotNullWhen(true)] out NewSubscriptionBulkPrice? value) + { + value = this.Value as NewSubscriptionBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickBulkWithFilters(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickBulkWithFilters( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackage(out var value)) { + /// // `value` is of type `NewSubscriptionPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackage( + [NotNullWhen(true)] out NewSubscriptionPackagePrice? value + ) + { + value = this.Value as NewSubscriptionPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrix(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrix( + [NotNullWhen(true)] out NewSubscriptionMatrixPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionThresholdTotalAmount(out var value)) { + /// // `value` is of type `NewSubscriptionThresholdTotalAmountPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionThresholdTotalAmount( + [NotNullWhen(true)] out NewSubscriptionThresholdTotalAmountPrice? value + ) + { + value = this.Value as NewSubscriptionThresholdTotalAmountPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackage( + [NotNullWhen(true)] out NewSubscriptionTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTiered(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTiered( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionTieredPackageWithMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionTieredPackageWithMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionTieredPackageWithMinimum( + [NotNullWhen(true)] out NewSubscriptionTieredPackageWithMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionTieredPackageWithMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionPackageWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionPackageWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionPackageWithAllocation( + [NotNullWhen(true)] out NewSubscriptionPackageWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionPackageWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithPercent(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithPercentPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithPercent( + [NotNullWhen(true)] out NewSubscriptionUnitWithPercentPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithPercentPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithAllocation( + [NotNullWhen(true)] out NewSubscriptionMatrixWithAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTieredWithProration(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTieredWithProration( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration? value + ) + { + value = + this.Value as SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionUnitWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionUnitWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionUnitWithProration( + [NotNullWhen(true)] out NewSubscriptionUnitWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionUnitWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedAllocation(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedAllocationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedAllocation( + [NotNullWhen(true)] out NewSubscriptionGroupedAllocationPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedAllocationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionBulkWithProration(out var value)) { + /// // `value` is of type `NewSubscriptionBulkWithProrationPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionBulkWithProration( + [NotNullWhen(true)] out NewSubscriptionBulkWithProrationPrice? value + ) + { + value = this.Value as NewSubscriptionBulkWithProrationPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithProratedMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithProratedMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithProratedMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithProratedMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithProratedMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedWithMeteredMinimum(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedWithMeteredMinimumPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedWithMeteredMinimum( + [NotNullWhen(true)] out NewSubscriptionGroupedWithMeteredMinimumPrice? value + ) + { + value = this.Value as NewSubscriptionGroupedWithMeteredMinimumPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGroupedWithMinMaxThresholds(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGroupedWithMinMaxThresholds( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds? value + ) + { + value = + this.Value + as SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMatrixWithDisplayName(out var value)) { + /// // `value` is of type `NewSubscriptionMatrixWithDisplayNamePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMatrixWithDisplayName( + [NotNullWhen(true)] out NewSubscriptionMatrixWithDisplayNamePrice? value + ) + { + value = this.Value as NewSubscriptionMatrixWithDisplayNamePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionGroupedTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionGroupedTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionGroupedTieredPackage( + [NotNullWhen(true)] out NewSubscriptionGroupedTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionGroupedTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMaxGroupTieredPackage(out var value)) { + /// // `value` is of type `NewSubscriptionMaxGroupTieredPackagePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMaxGroupTieredPackage( + [NotNullWhen(true)] out NewSubscriptionMaxGroupTieredPackagePrice? value + ) + { + value = this.Value as NewSubscriptionMaxGroupTieredPackagePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithUnitPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithUnitPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithUnitPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithUnitPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithUnitPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionScalableMatrixWithTieredPricing(out var value)) { + /// // `value` is of type `NewSubscriptionScalableMatrixWithTieredPricingPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionScalableMatrixWithTieredPricing( + [NotNullWhen(true)] out NewSubscriptionScalableMatrixWithTieredPricingPrice? value + ) + { + value = this.Value as NewSubscriptionScalableMatrixWithTieredPricingPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionCumulativeGroupedBulk(out var value)) { + /// // `value` is of type `NewSubscriptionCumulativeGroupedBulkPrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionCumulativeGroupedBulk( + [NotNullWhen(true)] out NewSubscriptionCumulativeGroupedBulkPrice? value + ) + { + value = this.Value as NewSubscriptionCumulativeGroupedBulkPrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickCumulativeGroupedAllocation(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickCumulativeGroupedAllocation( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation? value + ) + { + value = + this.Value + as SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickNewSubscriptionMinimumComposite(out var value)) { + /// // `value` is of type `NewSubscriptionMinimumCompositePrice` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickNewSubscriptionMinimumComposite( + [NotNullWhen(true)] out NewSubscriptionMinimumCompositePrice? value + ) + { + value = this.Value as NewSubscriptionMinimumCompositePrice; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickPercent(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsReplacePricePricePercent` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickPercent( + [NotNullWhen(true)] out SubscriptionSchedulePlanChangeParamsReplacePricePricePercent? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsReplacePricePricePercent; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickEventOutput(out var value)) { + /// // `value` is of type `SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickEventOutput( + [NotNullWhen(true)] + out SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput? value + ) + { + value = this.Value as SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePricePercent value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action newSubscriptionUnit, + System::Action newSubscriptionTiered, + System::Action newSubscriptionBulk, + System::Action bulkWithFilters, + System::Action newSubscriptionPackage, + System::Action newSubscriptionMatrix, + System::Action newSubscriptionThresholdTotalAmount, + System::Action newSubscriptionTieredPackage, + System::Action newSubscriptionTieredWithMinimum, + System::Action newSubscriptionGroupedTiered, + System::Action newSubscriptionTieredPackageWithMinimum, + System::Action newSubscriptionPackageWithAllocation, + System::Action newSubscriptionUnitWithPercent, + System::Action newSubscriptionMatrixWithAllocation, + System::Action tieredWithProration, + System::Action newSubscriptionUnitWithProration, + System::Action newSubscriptionGroupedAllocation, + System::Action newSubscriptionBulkWithProration, + System::Action newSubscriptionGroupedWithProratedMinimum, + System::Action newSubscriptionGroupedWithMeteredMinimum, + System::Action groupedWithMinMaxThresholds, + System::Action newSubscriptionMatrixWithDisplayName, + System::Action newSubscriptionGroupedTieredPackage, + System::Action newSubscriptionMaxGroupTieredPackage, + System::Action newSubscriptionScalableMatrixWithUnitPricing, + System::Action newSubscriptionScalableMatrixWithTieredPricing, + System::Action newSubscriptionCumulativeGroupedBulk, + System::Action cumulativeGroupedAllocation, + System::Action newSubscriptionMinimumComposite, + System::Action percent, + System::Action eventOutput + ) + { + switch (this.Value) + { + case NewSubscriptionUnitPrice value: + newSubscriptionUnit(value); + break; + case NewSubscriptionTieredPrice value: + newSubscriptionTiered(value); + break; + case NewSubscriptionBulkPrice value: + newSubscriptionBulk(value); + break; + case SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters value: + bulkWithFilters(value); + break; + case NewSubscriptionPackagePrice value: + newSubscriptionPackage(value); + break; + case NewSubscriptionMatrixPrice value: + newSubscriptionMatrix(value); + break; + case NewSubscriptionThresholdTotalAmountPrice value: + newSubscriptionThresholdTotalAmount(value); + break; + case NewSubscriptionTieredPackagePrice value: + newSubscriptionTieredPackage(value); + break; + case NewSubscriptionTieredWithMinimumPrice value: + newSubscriptionTieredWithMinimum(value); + break; + case NewSubscriptionGroupedTieredPrice value: + newSubscriptionGroupedTiered(value); + break; + case NewSubscriptionTieredPackageWithMinimumPrice value: + newSubscriptionTieredPackageWithMinimum(value); + break; + case NewSubscriptionPackageWithAllocationPrice value: + newSubscriptionPackageWithAllocation(value); + break; + case NewSubscriptionUnitWithPercentPrice value: + newSubscriptionUnitWithPercent(value); + break; + case NewSubscriptionMatrixWithAllocationPrice value: + newSubscriptionMatrixWithAllocation(value); + break; + case SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration value: + tieredWithProration(value); + break; + case NewSubscriptionUnitWithProrationPrice value: + newSubscriptionUnitWithProration(value); + break; + case NewSubscriptionGroupedAllocationPrice value: + newSubscriptionGroupedAllocation(value); + break; + case NewSubscriptionBulkWithProrationPrice value: + newSubscriptionBulkWithProration(value); + break; + case NewSubscriptionGroupedWithProratedMinimumPrice value: + newSubscriptionGroupedWithProratedMinimum(value); + break; + case NewSubscriptionGroupedWithMeteredMinimumPrice value: + newSubscriptionGroupedWithMeteredMinimum(value); + break; + case SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds value: + groupedWithMinMaxThresholds(value); + break; + case NewSubscriptionMatrixWithDisplayNamePrice value: + newSubscriptionMatrixWithDisplayName(value); + break; + case NewSubscriptionGroupedTieredPackagePrice value: + newSubscriptionGroupedTieredPackage(value); + break; + case NewSubscriptionMaxGroupTieredPackagePrice value: + newSubscriptionMaxGroupTieredPackage(value); + break; + case NewSubscriptionScalableMatrixWithUnitPricingPrice value: + newSubscriptionScalableMatrixWithUnitPricing(value); + break; + case NewSubscriptionScalableMatrixWithTieredPricingPrice value: + newSubscriptionScalableMatrixWithTieredPricing(value); + break; + case NewSubscriptionCumulativeGroupedBulkPrice value: + newSubscriptionCumulativeGroupedBulk(value); + break; + case SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation value: + cumulativeGroupedAllocation(value); + break; + case NewSubscriptionMinimumCompositePrice value: + newSubscriptionMinimumComposite(value); + break; + case SubscriptionSchedulePlanChangeParamsReplacePricePricePercent value: + percent(value); + break; + case SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput value: + eventOutput(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePrice" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (NewSubscriptionUnitPrice value) => {...}, + /// (NewSubscriptionTieredPrice value) => {...}, + /// (NewSubscriptionBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters value) => {...}, + /// (NewSubscriptionPackagePrice value) => {...}, + /// (NewSubscriptionMatrixPrice value) => {...}, + /// (NewSubscriptionThresholdTotalAmountPrice value) => {...}, + /// (NewSubscriptionTieredPackagePrice value) => {...}, + /// (NewSubscriptionTieredWithMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedTieredPrice value) => {...}, + /// (NewSubscriptionTieredPackageWithMinimumPrice value) => {...}, + /// (NewSubscriptionPackageWithAllocationPrice value) => {...}, + /// (NewSubscriptionUnitWithPercentPrice value) => {...}, + /// (NewSubscriptionMatrixWithAllocationPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration value) => {...}, + /// (NewSubscriptionUnitWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedAllocationPrice value) => {...}, + /// (NewSubscriptionBulkWithProrationPrice value) => {...}, + /// (NewSubscriptionGroupedWithProratedMinimumPrice value) => {...}, + /// (NewSubscriptionGroupedWithMeteredMinimumPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds value) => {...}, + /// (NewSubscriptionMatrixWithDisplayNamePrice value) => {...}, + /// (NewSubscriptionGroupedTieredPackagePrice value) => {...}, + /// (NewSubscriptionMaxGroupTieredPackagePrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithUnitPricingPrice value) => {...}, + /// (NewSubscriptionScalableMatrixWithTieredPricingPrice value) => {...}, + /// (NewSubscriptionCumulativeGroupedBulkPrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation value) => {...}, + /// (NewSubscriptionMinimumCompositePrice value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePricePercent value) => {...}, + /// (SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func newSubscriptionUnit, + System::Func newSubscriptionTiered, + System::Func newSubscriptionBulk, + System::Func< + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters, + T + > bulkWithFilters, + System::Func newSubscriptionPackage, + System::Func newSubscriptionMatrix, + System::Func< + NewSubscriptionThresholdTotalAmountPrice, + T + > newSubscriptionThresholdTotalAmount, + System::Func newSubscriptionTieredPackage, + System::Func newSubscriptionTieredWithMinimum, + System::Func newSubscriptionGroupedTiered, + System::Func< + NewSubscriptionTieredPackageWithMinimumPrice, + T + > newSubscriptionTieredPackageWithMinimum, + System::Func< + NewSubscriptionPackageWithAllocationPrice, + T + > newSubscriptionPackageWithAllocation, + System::Func newSubscriptionUnitWithPercent, + System::Func< + NewSubscriptionMatrixWithAllocationPrice, + T + > newSubscriptionMatrixWithAllocation, + System::Func< + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration, + T + > tieredWithProration, + System::Func newSubscriptionUnitWithProration, + System::Func newSubscriptionGroupedAllocation, + System::Func newSubscriptionBulkWithProration, + System::Func< + NewSubscriptionGroupedWithProratedMinimumPrice, + T + > newSubscriptionGroupedWithProratedMinimum, + System::Func< + NewSubscriptionGroupedWithMeteredMinimumPrice, + T + > newSubscriptionGroupedWithMeteredMinimum, + System::Func< + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds, + T + > groupedWithMinMaxThresholds, + System::Func< + NewSubscriptionMatrixWithDisplayNamePrice, + T + > newSubscriptionMatrixWithDisplayName, + System::Func< + NewSubscriptionGroupedTieredPackagePrice, + T + > newSubscriptionGroupedTieredPackage, + System::Func< + NewSubscriptionMaxGroupTieredPackagePrice, + T + > newSubscriptionMaxGroupTieredPackage, + System::Func< + NewSubscriptionScalableMatrixWithUnitPricingPrice, + T + > newSubscriptionScalableMatrixWithUnitPricing, + System::Func< + NewSubscriptionScalableMatrixWithTieredPricingPrice, + T + > newSubscriptionScalableMatrixWithTieredPricing, + System::Func< + NewSubscriptionCumulativeGroupedBulkPrice, + T + > newSubscriptionCumulativeGroupedBulk, + System::Func< + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation, + T + > cumulativeGroupedAllocation, + System::Func newSubscriptionMinimumComposite, + System::Func percent, + System::Func< + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput, + T + > eventOutput + ) + { + return this.Value switch + { + NewSubscriptionUnitPrice value => newSubscriptionUnit(value), + NewSubscriptionTieredPrice value => newSubscriptionTiered(value), + NewSubscriptionBulkPrice value => newSubscriptionBulk(value), + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters value => + bulkWithFilters(value), + NewSubscriptionPackagePrice value => newSubscriptionPackage(value), + NewSubscriptionMatrixPrice value => newSubscriptionMatrix(value), + NewSubscriptionThresholdTotalAmountPrice value => newSubscriptionThresholdTotalAmount( + value + ), + NewSubscriptionTieredPackagePrice value => newSubscriptionTieredPackage(value), + NewSubscriptionTieredWithMinimumPrice value => newSubscriptionTieredWithMinimum(value), + NewSubscriptionGroupedTieredPrice value => newSubscriptionGroupedTiered(value), + NewSubscriptionTieredPackageWithMinimumPrice value => + newSubscriptionTieredPackageWithMinimum(value), + NewSubscriptionPackageWithAllocationPrice value => newSubscriptionPackageWithAllocation( + value + ), + NewSubscriptionUnitWithPercentPrice value => newSubscriptionUnitWithPercent(value), + NewSubscriptionMatrixWithAllocationPrice value => newSubscriptionMatrixWithAllocation( + value + ), + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration value => + tieredWithProration(value), + NewSubscriptionUnitWithProrationPrice value => newSubscriptionUnitWithProration(value), + NewSubscriptionGroupedAllocationPrice value => newSubscriptionGroupedAllocation(value), + NewSubscriptionBulkWithProrationPrice value => newSubscriptionBulkWithProration(value), + NewSubscriptionGroupedWithProratedMinimumPrice value => + newSubscriptionGroupedWithProratedMinimum(value), + NewSubscriptionGroupedWithMeteredMinimumPrice value => + newSubscriptionGroupedWithMeteredMinimum(value), + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds value => + groupedWithMinMaxThresholds(value), + NewSubscriptionMatrixWithDisplayNamePrice value => newSubscriptionMatrixWithDisplayName( + value + ), + NewSubscriptionGroupedTieredPackagePrice value => newSubscriptionGroupedTieredPackage( + value + ), + NewSubscriptionMaxGroupTieredPackagePrice value => newSubscriptionMaxGroupTieredPackage( + value + ), + NewSubscriptionScalableMatrixWithUnitPricingPrice value => + newSubscriptionScalableMatrixWithUnitPricing(value), + NewSubscriptionScalableMatrixWithTieredPricingPrice value => + newSubscriptionScalableMatrixWithTieredPricing(value), + NewSubscriptionCumulativeGroupedBulkPrice value => newSubscriptionCumulativeGroupedBulk( + value + ), + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation value => + cumulativeGroupedAllocation(value), + NewSubscriptionMinimumCompositePrice value => newSubscriptionMinimumComposite(value), + SubscriptionSchedulePlanChangeParamsReplacePricePricePercent value => percent(value), + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput value => eventOutput( + value + ), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePrice" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionUnitPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionBulkPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMatrixPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionThresholdTotalAmountPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredWithMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedTieredPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionTieredPackageWithMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionPackageWithAllocationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionUnitWithPercentPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMatrixWithAllocationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionUnitWithProrationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedAllocationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionBulkWithProrationPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedWithProratedMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedWithMeteredMinimumPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMatrixWithDisplayNamePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionGroupedTieredPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMaxGroupTieredPackagePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionScalableMatrixWithUnitPricingPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionScalableMatrixWithTieredPricingPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionCumulativeGroupedBulkPrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + NewSubscriptionMinimumCompositePrice value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePricePercent value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePrice( + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePrice" + ); + } + this.Switch( + (newSubscriptionUnit) => newSubscriptionUnit.Validate(), + (newSubscriptionTiered) => newSubscriptionTiered.Validate(), + (newSubscriptionBulk) => newSubscriptionBulk.Validate(), + (bulkWithFilters) => bulkWithFilters.Validate(), + (newSubscriptionPackage) => newSubscriptionPackage.Validate(), + (newSubscriptionMatrix) => newSubscriptionMatrix.Validate(), + (newSubscriptionThresholdTotalAmount) => newSubscriptionThresholdTotalAmount.Validate(), + (newSubscriptionTieredPackage) => newSubscriptionTieredPackage.Validate(), + (newSubscriptionTieredWithMinimum) => newSubscriptionTieredWithMinimum.Validate(), + (newSubscriptionGroupedTiered) => newSubscriptionGroupedTiered.Validate(), + (newSubscriptionTieredPackageWithMinimum) => + newSubscriptionTieredPackageWithMinimum.Validate(), + (newSubscriptionPackageWithAllocation) => + newSubscriptionPackageWithAllocation.Validate(), + (newSubscriptionUnitWithPercent) => newSubscriptionUnitWithPercent.Validate(), + (newSubscriptionMatrixWithAllocation) => newSubscriptionMatrixWithAllocation.Validate(), + (tieredWithProration) => tieredWithProration.Validate(), + (newSubscriptionUnitWithProration) => newSubscriptionUnitWithProration.Validate(), + (newSubscriptionGroupedAllocation) => newSubscriptionGroupedAllocation.Validate(), + (newSubscriptionBulkWithProration) => newSubscriptionBulkWithProration.Validate(), + (newSubscriptionGroupedWithProratedMinimum) => + newSubscriptionGroupedWithProratedMinimum.Validate(), + (newSubscriptionGroupedWithMeteredMinimum) => + newSubscriptionGroupedWithMeteredMinimum.Validate(), + (groupedWithMinMaxThresholds) => groupedWithMinMaxThresholds.Validate(), + (newSubscriptionMatrixWithDisplayName) => + newSubscriptionMatrixWithDisplayName.Validate(), + (newSubscriptionGroupedTieredPackage) => newSubscriptionGroupedTieredPackage.Validate(), + (newSubscriptionMaxGroupTieredPackage) => + newSubscriptionMaxGroupTieredPackage.Validate(), + (newSubscriptionScalableMatrixWithUnitPricing) => + newSubscriptionScalableMatrixWithUnitPricing.Validate(), + (newSubscriptionScalableMatrixWithTieredPricing) => + newSubscriptionScalableMatrixWithTieredPricing.Validate(), + (newSubscriptionCumulativeGroupedBulk) => + newSubscriptionCumulativeGroupedBulk.Validate(), + (cumulativeGroupedAllocation) => cumulativeGroupedAllocation.Validate(), + (newSubscriptionMinimumComposite) => newSubscriptionMinimumComposite.Validate(), + (percent) => percent.Validate(), + (eventOutput) => eventOutput.Validate() + ); + } + + public virtual bool Equals(SubscriptionSchedulePlanChangeParamsReplacePricePrice? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePrice? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? modelType; + try + { + modelType = element.GetProperty("model_type").GetString(); + } + catch + { + modelType = null; + } + + switch (modelType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_filters": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "threshold_total_amount": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_package_with_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "package_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "unit_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "bulk_with_proration": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_prorated_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_metered_minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_with_min_max_thresholds": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "matrix_with_display_name": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "grouped_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "max_group_tiered_package": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_unit_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "scalable_matrix_with_tiered_pricing": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_bulk": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "cumulative_grouped_allocation": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "minimum": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "percent": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "event_output": + { + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePrice(element); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePrice? value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value?.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + : JsonModel +{ + /// + /// Configuration for bulk_with_filters pricing + /// + public required SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig BulkWithFiltersConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "bulk_with_filters_config" + ); + } + init { JsonModel.Set(this._rawData, "bulk_with_filters_config", value); } + } + + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.BulkWithFiltersConfig.Validate(); + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"bulk_with_filters\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters() + { + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"bulk_with_filters\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFilters.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for bulk_with_filters pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + : JsonModel +{ + /// + /// Property filters to apply (all must match) + /// + public required IReadOnlyList Filters + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "filters"); + } + init { JsonModel.Set(this._rawData, "filters", value); } + } + + /// + /// Bulk tiers for rating based on total usage volume + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Filters) + { + item.Validate(); + } + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single property filter +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + : JsonModel +{ + /// + /// Event property key to filter on + /// + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + /// + /// Event property value to match + /// + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilterFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigFilter.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single bulk pricing tier +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + : JsonModel +{ + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// The lower bound for this tier + /// + public string? TierLowerBound + { + get { return JsonModel.GetNullableClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + public override void Validate() + { + _ = this.UnitAmount; + _ = this.TierLowerBound; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier( + string unitAmount + ) + : this() + { + this.UnitAmount = unitAmount; + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTierFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersBulkWithFiltersConfigTier.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceBulkWithFiltersConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for tiered_with_proration pricing + /// + public required SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig TieredWithProrationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "tiered_with_proration_config" + ); + } + init { JsonModel.Set(this._rawData, "tiered_with_proration_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"tiered_with_proration\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.TieredWithProrationConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration() + { + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration( + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration subscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"tiered_with_proration\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProration.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for tiered_with_proration pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + : JsonModel +{ + /// + /// Tiers for rating based on total usage quantities into the specified tier + /// with proration + /// + public required IReadOnlyList Tiers + { + get + { + return JsonModel.GetNotNullClass< + List + >(this.RawData, "tiers"); + } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Tiers) + { + item.Validate(); + } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig( + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig subscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig( + List tiers + ) + : this() + { + this.Tiers = tiers; + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfig.FromRawUnchecked( + rawData + ); +} + +/// +/// Configuration for a single tiered with proration tier +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + : JsonModel +{ + /// + /// Inclusive tier starting value + /// + public required string TierLowerBound + { + get { return JsonModel.GetNotNullClass(this.RawData, "tier_lower_bound"); } + init { JsonModel.Set(this._rawData, "tier_lower_bound", value); } + } + + /// + /// Amount per unit + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.TierLowerBound; + _ = this.UnitAmount; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier subscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTierFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationTieredWithProrationConfigTier.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceTieredWithProrationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds, + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for grouped_with_min_max_thresholds pricing + /// + public required SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig GroupedWithMinMaxThresholdsConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "grouped_with_min_max_thresholds_config" + ); + } + init { JsonModel.Set(this._rawData, "grouped_with_min_max_thresholds_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.GroupedWithMinMaxThresholdsConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"grouped_with_min_max_thresholds\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds() + { + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds( + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds subscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"grouped_with_min_max_thresholds\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholds.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom, + _ => + (SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for grouped_with_min_max_thresholds pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig, + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + : JsonModel +{ + /// + /// The event property used to group before applying thresholds + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The maximum amount to charge each group + /// + public required string MaximumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "maximum_charge"); } + init { JsonModel.Set(this._rawData, "maximum_charge", value); } + } + + /// + /// The minimum amount to charge each group, regardless of usage + /// + public required string MinimumCharge + { + get { return JsonModel.GetNotNullClass(this.RawData, "minimum_charge"); } + init { JsonModel.Set(this._rawData, "minimum_charge", value); } + } + + /// + /// The base price charged per group + /// + public required string PerUnitRate + { + get { return JsonModel.GetNotNullClass(this.RawData, "per_unit_rate"); } + init { JsonModel.Set(this._rawData, "per_unit_rate", value); } + } + + /// + public override void Validate() + { + _ = this.GroupingKey; + _ = this.MaximumCharge; + _ = this.MinimumCharge; + _ = this.PerUnitRate; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig subscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsGroupedWithMinMaxThresholdsConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceGroupedWithMinMaxThresholdsConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation, + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for cumulative_grouped_allocation pricing + /// + public required SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig CumulativeGroupedAllocationConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "cumulative_grouped_allocation_config" + ); + } + init { JsonModel.Set(this._rawData, "cumulative_grouped_allocation_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.CumulativeGroupedAllocationConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"cumulative_grouped_allocation\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation() + { + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation( + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation subscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize( + "\"cumulative_grouped_allocation\"" + ); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocation.FromRawUnchecked( + rawData + ); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Custom, + _ => + (SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence)( + -1 + ), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for cumulative_grouped_allocation pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig, + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + : JsonModel +{ + /// + /// The overall allocation across all groups + /// + public required string CumulativeAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "cumulative_allocation"); } + init { JsonModel.Set(this._rawData, "cumulative_allocation", value); } + } + + /// + /// The allocation per individual group + /// + public required string GroupAllocation + { + get { return JsonModel.GetNotNullClass(this.RawData, "group_allocation"); } + init { JsonModel.Set(this._rawData, "group_allocation", value); } + } + + /// + /// The event property used to group usage before applying allocations + /// + public required string GroupingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + /// The amount to charge for each unit outside of the allocation + /// + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.CumulativeAllocation; + _ = this.GroupAllocation; + _ = this.GroupingKey; + _ = this.UnitAmount; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig() + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig subscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) + : base( + subscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig + ) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationCumulativeGroupedAllocationConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceCumulativeGroupedAllocationConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePricePercent, + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePricePercent : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// Configuration for percent pricing + /// + public required SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig PercentConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "percent_config" + ); + } + init { JsonModel.Set(this._rawData, "percent_config", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"percent\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + this.PercentConfig.Validate(); + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercent() + { + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercent( + SubscriptionSchedulePlanChangeParamsReplacePricePricePercent subscriptionSchedulePlanChangeParamsReplacePricePricePercent + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePricePercent) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercent( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"percent\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePricePercent( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercent FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsReplacePricePricePercent.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.OneTime, + "custom" => SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for percent pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig, + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig + : JsonModel +{ + /// + /// What percent of the component subtotals to charge + /// + public required double Percent + { + get { return JsonModel.GetNotNullStruct(this.RawData, "percent"); } + init { JsonModel.Set(this._rawData, "percent", value); } + } + + /// + public override void Validate() + { + _ = this.Percent; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig() { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig( + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig subscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig(double percent) + : this() + { + this.Percent = percent; + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentPercentConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePricePercentConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput, + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + : JsonModel +{ + /// + /// The cadence to bill for this price on. + /// + public required ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > Cadence + { + get + { + return JsonModel.GetNotNullClass< + ApiEnum< + string, + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence + > + >(this.RawData, "cadence"); + } + init { JsonModel.Set(this._rawData, "cadence", value); } + } + + /// + /// Configuration for event_output pricing + /// + public required SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig EventOutputConfig + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "event_output_config" + ); + } + init { JsonModel.Set(this._rawData, "event_output_config", value); } + } + + /// + /// The id of the item the price will be associated with. + /// + public required string ItemID + { + get { return JsonModel.GetNotNullClass(this.RawData, "item_id"); } + init { JsonModel.Set(this._rawData, "item_id", value); } + } + + /// + /// The pricing model type + /// + public JsonElement ModelType + { + get { return JsonModel.GetNotNullStruct(this.RawData, "model_type"); } + init { JsonModel.Set(this._rawData, "model_type", value); } + } + + /// + /// The name of the price. + /// + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + /// The id of the billable metric for the price. Only needed if the price is usage-based. + /// + public string? BillableMetricID + { + get { return JsonModel.GetNullableClass(this.RawData, "billable_metric_id"); } + init { JsonModel.Set(this._rawData, "billable_metric_id", value); } + } + + /// + /// If the Price represents a fixed cost, the price will be billed in-advance + /// if this is true, and in-arrears if this is false. + /// + public bool? BilledInAdvance + { + get { return JsonModel.GetNullableStruct(this.RawData, "billed_in_advance"); } + init { JsonModel.Set(this._rawData, "billed_in_advance", value); } + } + + /// + /// For custom cadence: specifies the duration of the billing period in days + /// or months. + /// + public NewBillingCycleConfiguration? BillingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "billing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "billing_cycle_configuration", value); } + } + + /// + /// The per unit conversion rate of the price currency to the invoicing currency. + /// + public double? ConversionRate + { + get { return JsonModel.GetNullableStruct(this.RawData, "conversion_rate"); } + init { JsonModel.Set(this._rawData, "conversion_rate", value); } + } + + /// + /// The configuration for the rate of the price currency to the invoicing currency. + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig? ConversionRateConfig + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "conversion_rate_config" + ); + } + init { JsonModel.Set(this._rawData, "conversion_rate_config", value); } + } + + /// + /// An ISO 4217 currency string, or custom pricing unit identifier, in which + /// this price is billed. + /// + public string? Currency + { + get { return JsonModel.GetNullableClass(this.RawData, "currency"); } + init { JsonModel.Set(this._rawData, "currency", value); } + } + + /// + /// For dimensional price: specifies a price group and dimension values + /// + public NewDimensionalPriceConfiguration? DimensionalPriceConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "dimensional_price_configuration" + ); + } + init { JsonModel.Set(this._rawData, "dimensional_price_configuration", value); } + } + + /// + /// An alias for the price. + /// + public string? ExternalPriceID + { + get { return JsonModel.GetNullableClass(this.RawData, "external_price_id"); } + init { JsonModel.Set(this._rawData, "external_price_id", value); } + } + + /// + /// If the Price represents a fixed cost, this represents the quantity of units applied. + /// + public double? FixedPriceQuantity + { + get { return JsonModel.GetNullableStruct(this.RawData, "fixed_price_quantity"); } + init { JsonModel.Set(this._rawData, "fixed_price_quantity", value); } + } + + /// + /// The property used to group this price on an invoice + /// + public string? InvoiceGroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "invoice_grouping_key"); } + init { JsonModel.Set(this._rawData, "invoice_grouping_key", value); } + } + + /// + /// Within each billing cycle, specifies the cadence at which invoices are produced. + /// If unspecified, a single invoice is produced per billing cycle. + /// + public NewBillingCycleConfiguration? InvoicingCycleConfiguration + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "invoicing_cycle_configuration" + ); + } + init { JsonModel.Set(this._rawData, "invoicing_cycle_configuration", value); } + } + + /// + /// User-specified key/value pairs for the resource. Individual keys can be removed + /// by setting the value to `null`, and the entire metadata mapping can be cleared + /// by setting `metadata` to `null`. + /// + public IReadOnlyDictionary? Metadata + { + get + { + return JsonModel.GetNullableClass>( + this.RawData, + "metadata" + ); + } + init { JsonModel.Set(this._rawData, "metadata", value); } + } + + /// + /// A transient ID that can be used to reference this price when adding adjustments + /// in the same API call. + /// + public string? ReferenceID + { + get { return JsonModel.GetNullableClass(this.RawData, "reference_id"); } + init { JsonModel.Set(this._rawData, "reference_id", value); } + } + + /// + public override void Validate() + { + this.Cadence.Validate(); + this.EventOutputConfig.Validate(); + _ = this.ItemID; + if ( + !JsonElement.DeepEquals( + this.ModelType, + JsonSerializer.Deserialize("\"event_output\"") + ) + ) + { + throw new OrbInvalidDataException("Invalid value given for constant"); + } + _ = this.Name; + _ = this.BillableMetricID; + _ = this.BilledInAdvance; + this.BillingCycleConfiguration?.Validate(); + _ = this.ConversionRate; + this.ConversionRateConfig?.Validate(); + _ = this.Currency; + this.DimensionalPriceConfiguration?.Validate(); + _ = this.ExternalPriceID; + _ = this.FixedPriceQuantity; + _ = this.InvoiceGroupingKey; + this.InvoicingCycleConfiguration?.Validate(); + _ = this.Metadata; + _ = this.ReferenceID; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput() + { + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput( + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput subscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput) { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + + this.ModelType = JsonSerializer.Deserialize("\"event_output\""); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutput.FromRawUnchecked(rawData); +} + +/// +/// The cadence to bill for this price on. +/// +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadenceConverter) +)] +public enum SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence +{ + Annual, + SemiAnnual, + Monthly, + Quarterly, + OneTime, + Custom, +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadenceConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual, + "semi_annual" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.SemiAnnual, + "monthly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Monthly, + "quarterly" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Quarterly, + "one_time" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.OneTime, + "custom" => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Custom, + _ => (SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Annual => + "annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.SemiAnnual => + "semi_annual", + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Monthly => + "monthly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Quarterly => + "quarterly", + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.OneTime => + "one_time", + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputCadence.Custom => + "custom", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Configuration for event_output pricing +/// +[JsonConverter( + typeof(JsonModelConverter< + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig, + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfigFromRaw + >) +)] +public sealed record class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + : JsonModel +{ + /// + /// The key in the event data to extract the unit rate from. + /// + public required string UnitRatingKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_rating_key"); } + init { JsonModel.Set(this._rawData, "unit_rating_key", value); } + } + + /// + /// If provided, this amount will be used as the unit rate when an event does + /// not have a value for the `unit_rating_key`. If not provided, events missing + /// a unit rate will be ignored. + /// + public string? DefaultUnitRate + { + get { return JsonModel.GetNullableClass(this.RawData, "default_unit_rate"); } + init { JsonModel.Set(this._rawData, "default_unit_rate", value); } + } + + /// + /// An optional key in the event data to group by (e.g., event ID). All events + /// will also be grouped by their unit rate. + /// + public string? GroupingKey + { + get { return JsonModel.GetNullableClass(this.RawData, "grouping_key"); } + init { JsonModel.Set(this._rawData, "grouping_key", value); } + } + + /// + public override void Validate() + { + _ = this.UnitRatingKey; + _ = this.DefaultUnitRate; + _ = this.GroupingKey; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig() { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig( + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig subscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig + ) + : base(subscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig) + { } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig( + FrozenDictionary rawData + ) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig( + string unitRatingKey + ) + : this() + { + this.UnitRatingKey = unitRatingKey; + } +} + +class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfigFromRaw + : IFromRawJson +{ + /// + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputEventOutputConfig.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfigConverter) +)] +public record class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig( + JsonElement element + ) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnit(out var value)) { + /// // `value` is of type `SharedUnitConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnit([NotNullWhen(true)] out SharedUnitConversionRateConfig? value) + { + value = this.Value as SharedUnitConversionRateConfig; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickTiered(out var value)) { + /// // `value` is of type `SharedTieredConversionRateConfig` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickTiered([NotNullWhen(true)] out SharedTieredConversionRateConfig? value) + { + value = this.Value as SharedTieredConversionRateConfig; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action unit, + System::Action tiered + ) + { + switch (this.Value) + { + case SharedUnitConversionRateConfig value: + unit(value); + break; + case SharedTieredConversionRateConfig value: + tiered(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (SharedUnitConversionRateConfig value) => {...}, + /// (SharedTieredConversionRateConfig value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func unit, + System::Func tiered + ) + { + return this.Value switch + { + SharedUnitConversionRateConfig value => unit(value), + SharedTieredConversionRateConfig value => tiered(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig" + ), + }; + } + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig( + SharedUnitConversionRateConfig value + ) => new(value); + + public static implicit operator SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig( + SharedTieredConversionRateConfig value + ) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig" + ); + } + this.Switch((unit) => unit.Validate(), (tiered) => tiered.Validate()); + } + + public virtual bool Equals( + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig? other + ) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfigConverter + : JsonConverter +{ + public override SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + string? conversionRateType; + try + { + conversionRateType = element.GetProperty("conversion_rate_type").GetString(); + } + catch + { + conversionRateType = null; + } + + switch (conversionRateType) + { + case "unit": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + case "tiered": + { + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) + when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + default: + { + return new SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig( + element + ); + } + } + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionSchedulePlanChangeParamsReplacePricePriceEventOutputConversionRateConfig value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustment.cs deleted file mode 100644 index 3cbeba82..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustment.cs +++ /dev/null @@ -1,108 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddAdjustmentProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the subscription. - /// - public required AddAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the adjustment interval. This is the date that the adjustment - /// will stop affecting prices on the subscription. - /// - public System::DateTime? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this adjustment to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The start date of the adjustment interval. This is the date that the adjustment - /// will start affecting prices on the subscription. If null, the adjustment will - /// start when the phase or subscription starts. - /// - public System::DateTime? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.EndDate; - _ = this.PlanPhaseOrder; - _ = this.StartDate; - } - - public AddAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustmentProperties/Adjustment.cs deleted file mode 100644 index 348ab66f..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index c0e05eb9..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using AddAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddAdjustmentProperties; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : AddAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPrice.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPrice.cs deleted file mode 100644 index 24e1a30c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPrice.cs +++ /dev/null @@ -1,215 +0,0 @@ -using AddPriceProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddPriceProperties; -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class AddPrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new allocation price to create and add to the subscription. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for this price. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The end date of the price interval. This is the date that the price will stop - /// billing on the subscription. If null, billing will end when the phase or subscription ends. - /// - public System::DateTime? EndDate - { - get - { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external price id of the price to add to the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount - /// for this price. - /// - public string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount - /// for this price. - /// - public string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The phase to add this price to. - /// - public long? PlanPhaseOrder - { - get - { - if (!this.Properties.TryGetValue("plan_phase_order", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["plan_phase_order"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The definition of a new price to create and add to the subscription. - /// - public AddPriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the price to add to the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The start date of the price interval. This is the date that the price will - /// start billing on the subscription. If null, billing will start when the phase - /// or subscription starts. - /// - public System::DateTime? StartDate - { - get - { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.AllocationPrice?.Validate(); - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - _ = this.EndDate; - _ = this.ExternalPriceID; - _ = this.MaximumAmount; - _ = this.MinimumAmount; - _ = this.PlanPhaseOrder; - this.Price?.Validate(); - _ = this.PriceID; - _ = this.StartDate; - } - - public AddPrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - AddPrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static AddPrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPriceProperties/Price.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPriceProperties/Price.cs deleted file mode 100644 index 5bfae501..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPriceProperties/Price.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Orb = Orb; -using PriceVariants = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddPriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddPriceProperties; - -/// -/// The definition of a new price to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewSubscriptionUnitPrice Create( - Subscriptions::NewSubscriptionUnitPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackagePrice Create( - Subscriptions::NewSubscriptionPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixPrice Create( - Subscriptions::NewSubscriptionMatrixPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPrice Create( - Subscriptions::NewSubscriptionTieredPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredBPSPrice Create( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBPSPrice Create( - Subscriptions::NewSubscriptionBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkBPSPrice Create( - Subscriptions::NewSubscriptionBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkPrice Create( - Subscriptions::NewSubscriptionBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionThresholdTotalAmountPrice Create( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackagePrice Create( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithPercentPrice Create( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackageWithAllocationPrice Create( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTierWithProrationPrice Create( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithProrationPrice Create( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedAllocationPrice Create( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithProratedMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkWithProrationPrice Create( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithUnitPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithTieredPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionCumulativeGroupedBulkPrice Create( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMaxGroupTieredPackagePrice Create( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithMeteredMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithDisplayNamePrice Create( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPackagePrice Create( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithAllocationPrice Create( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackageWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPrice Create( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPriceProperties/PriceVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPriceProperties/PriceVariants/All.cs deleted file mode 100644 index aee850e7..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/AddPriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,737 +0,0 @@ -using AddPriceProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddPriceProperties; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.AddPriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionUnitPrice(Subscriptions::NewSubscriptionUnitPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionUnitPrice From(Subscriptions::NewSubscriptionUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackagePrice, - Subscriptions::NewSubscriptionPackagePrice - >) -)] -public sealed record class NewSubscriptionPackagePrice( - Subscriptions::NewSubscriptionPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionPackagePrice From(Subscriptions::NewSubscriptionPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixPrice, - Subscriptions::NewSubscriptionMatrixPrice - >) -)] -public sealed record class NewSubscriptionMatrixPrice( - Subscriptions::NewSubscriptionMatrixPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionMatrixPrice From(Subscriptions::NewSubscriptionMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPrice, - Subscriptions::NewSubscriptionTieredPrice - >) -)] -public sealed record class NewSubscriptionTieredPrice( - Subscriptions::NewSubscriptionTieredPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredPrice From(Subscriptions::NewSubscriptionTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredBPSPrice, - Subscriptions::NewSubscriptionTieredBPSPrice - >) -)] -public sealed record class NewSubscriptionTieredBPSPrice( - Subscriptions::NewSubscriptionTieredBPSPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredBPSPrice From( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBPSPrice(Subscriptions::NewSubscriptionBPSPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBPSPrice From(Subscriptions::NewSubscriptionBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkBPSPrice, - Subscriptions::NewSubscriptionBulkBPSPrice - >) -)] -public sealed record class NewSubscriptionBulkBPSPrice( - Subscriptions::NewSubscriptionBulkBPSPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkBPSPrice From(Subscriptions::NewSubscriptionBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBulkPrice(Subscriptions::NewSubscriptionBulkPrice Value) - : AddPriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkPrice From(Subscriptions::NewSubscriptionBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - >) -)] -public sealed record class NewSubscriptionThresholdTotalAmountPrice( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - > -{ - public static NewSubscriptionThresholdTotalAmountPrice From( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionTieredPackagePrice( - Subscriptions::NewSubscriptionTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - > -{ - public static NewSubscriptionTieredPackagePrice From( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredWithMinimumPrice( - Subscriptions::NewSubscriptionTieredWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - > -{ - public static NewSubscriptionTieredWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - >) -)] -public sealed record class NewSubscriptionUnitWithPercentPrice( - Subscriptions::NewSubscriptionUnitWithPercentPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - > -{ - public static NewSubscriptionUnitWithPercentPrice From( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionPackageWithAllocationPrice( - Subscriptions::NewSubscriptionPackageWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - > -{ - public static NewSubscriptionPackageWithAllocationPrice From( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - >) -)] -public sealed record class NewSubscriptionTierWithProrationPrice( - Subscriptions::NewSubscriptionTierWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - > -{ - public static NewSubscriptionTierWithProrationPrice From( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - >) -)] -public sealed record class NewSubscriptionUnitWithProrationPrice( - Subscriptions::NewSubscriptionUnitWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - > -{ - public static NewSubscriptionUnitWithProrationPrice From( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - >) -)] -public sealed record class NewSubscriptionGroupedAllocationPrice( - Subscriptions::NewSubscriptionGroupedAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - > -{ - public static NewSubscriptionGroupedAllocationPrice From( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - > -{ - public static NewSubscriptionGroupedWithProratedMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - >) -)] -public sealed record class NewSubscriptionBulkWithProrationPrice( - Subscriptions::NewSubscriptionBulkWithProrationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - > -{ - public static NewSubscriptionBulkWithProrationPrice From( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithUnitPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithTieredPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewSubscriptionCumulativeGroupedBulkPrice( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - > -{ - public static NewSubscriptionCumulativeGroupedBulkPrice From( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionMaxGroupTieredPackagePrice( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - > -{ - public static NewSubscriptionMaxGroupTieredPackagePrice From( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - > -{ - public static NewSubscriptionGroupedWithMeteredMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewSubscriptionMatrixWithDisplayNamePrice( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - > -{ - public static NewSubscriptionMatrixWithDisplayNamePrice From( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPackagePrice( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - > -{ - public static NewSubscriptionGroupedTieredPackagePrice From( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionMatrixWithAllocationPrice( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - > -{ - public static NewSubscriptionMatrixWithAllocationPrice From( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredPackageWithMinimumPrice( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - > -{ - public static NewSubscriptionTieredPackageWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPrice( - Subscriptions::NewSubscriptionGroupedTieredPrice Value -) - : AddPriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - > -{ - public static NewSubscriptionGroupedTieredPrice From( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/BillingCycleAlignment.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/BillingCycleAlignment.cs deleted file mode 100644 index 317d083c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/BillingCycleAlignment.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -/// -/// Reset billing periods to be aligned with the plan change's effective date or -/// start of the month. Defaults to `unchanged` which keeps subscription's existing -/// billing cycle alignment. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class BillingCycleAlignment(string value) - : Orb::IEnum -{ - public static readonly BillingCycleAlignment Unchanged = new("unchanged"); - - public static readonly BillingCycleAlignment PlanChangeDate = new("plan_change_date"); - - public static readonly BillingCycleAlignment StartOfMonth = new("start_of_month"); - - readonly string _value = value; - - public enum Value - { - Unchanged, - PlanChangeDate, - StartOfMonth, - } - - public Value Known() => - _value switch - { - "unchanged" => Value.Unchanged, - "plan_change_date" => Value.PlanChangeDate, - "start_of_month" => Value.StartOfMonth, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static BillingCycleAlignment FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ChangeOption.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ChangeOption.cs deleted file mode 100644 index a763dd21..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ChangeOption.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ChangeOption(string value) : Orb::IEnum -{ - public static readonly ChangeOption RequestedDate = new("requested_date"); - - public static readonly ChangeOption EndOfSubscriptionTerm = new("end_of_subscription_term"); - - public static readonly ChangeOption Immediate = new("immediate"); - - readonly string _value = value; - - public enum Value - { - RequestedDate, - EndOfSubscriptionTerm, - Immediate, - } - - public Value Known() => - _value switch - { - "requested_date" => Value.RequestedDate, - "end_of_subscription_term" => Value.EndOfSubscriptionTerm, - "immediate" => Value.Immediate, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ChangeOption FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/RemoveAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/RemoveAdjustment.cs deleted file mode 100644 index 59b46dd3..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/RemoveAdjustment.cs +++ /dev/null @@ -1,53 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemoveAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the adjustment to remove on the subscription. - /// - public required string AdjustmentID - { - get - { - if (!this.Properties.TryGetValue("adjustment_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("adjustment_id"); - } - set { this.Properties["adjustment_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.AdjustmentID; - } - - public RemoveAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemoveAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemoveAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/RemovePrice.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/RemovePrice.cs deleted file mode 100644 index ffbcd70c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/RemovePrice.cs +++ /dev/null @@ -1,67 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class RemovePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The external price id of the price to remove on the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The id of the price to remove on the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ExternalPriceID; - _ = this.PriceID; - } - - public RemovePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - RemovePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static RemovePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustment.cs deleted file mode 100644 index 0818279f..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustment.cs +++ /dev/null @@ -1,85 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplaceAdjustment : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The definition of a new adjustment to create and add to the subscription. - /// - public required ReplaceAdjustmentProperties::Adjustment Adjustment - { - get - { - if (!this.Properties.TryGetValue("adjustment", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "adjustment", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("adjustment"); - } - set { this.Properties["adjustment"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the adjustment on the plan to replace in the subscription. - /// - public required string ReplacesAdjustmentID - { - get - { - if ( - !this.Properties.TryGetValue( - "replaces_adjustment_id", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "replaces_adjustment_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_adjustment_id"); - } - set - { - this.Properties["replaces_adjustment_id"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public override void Validate() - { - this.Adjustment.Validate(); - _ = this.ReplacesAdjustmentID; - } - - public ReplaceAdjustment() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplaceAdjustment(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplaceAdjustment FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs deleted file mode 100644 index 1f41f589..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustmentProperties/Adjustment.cs +++ /dev/null @@ -1,31 +0,0 @@ -using AdjustmentVariants = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplaceAdjustmentProperties; - -/// -/// The definition of a new adjustment to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Adjustment -{ - internal Adjustment() { } - - public static AdjustmentVariants::NewPercentageDiscount Create( - Models::NewPercentageDiscount value - ) => new(value); - - public static AdjustmentVariants::NewUsageDiscount Create(Models::NewUsageDiscount value) => - new(value); - - public static AdjustmentVariants::NewAmountDiscount Create(Models::NewAmountDiscount value) => - new(value); - - public static AdjustmentVariants::NewMinimum Create(Models::NewMinimum value) => new(value); - - public static AdjustmentVariants::NewMaximum Create(Models::NewMaximum value) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs deleted file mode 100644 index bccf2497..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplaceAdjustmentProperties/AdjustmentVariants/All.cs +++ /dev/null @@ -1,92 +0,0 @@ -using Models = Orb.Models; -using Orb = Orb; -using ReplaceAdjustmentProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplaceAdjustmentProperties; -using Serialization = System.Text.Json.Serialization; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplaceAdjustmentProperties.AdjustmentVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewPercentageDiscount(Models::NewPercentageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewPercentageDiscount From(Models::NewPercentageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewUsageDiscount(Models::NewUsageDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewUsageDiscount From(Models::NewUsageDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewAmountDiscount(Models::NewAmountDiscount Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewAmountDiscount From(Models::NewAmountDiscount value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMinimum(Models::NewMinimum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMinimum From(Models::NewMinimum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class NewMaximum(Models::NewMaximum Value) - : ReplaceAdjustmentProperties::Adjustment, - Orb::IVariant -{ - public static NewMaximum From(Models::NewMaximum value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePrice.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePrice.cs deleted file mode 100644 index 348233a7..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePrice.cs +++ /dev/null @@ -1,206 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class ReplacePrice : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// The id of the price on the plan to replace in the subscription. - /// - public required string ReplacesPriceID - { - get - { - if (!this.Properties.TryGetValue("replaces_price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "replaces_price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("replaces_price_id"); - } - set - { - this.Properties["replaces_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The definition of a new allocation price to create and add to the subscription. - /// - public Models::NewAllocationPrice? AllocationPrice - { - get - { - if (!this.Properties.TryGetValue("allocation_price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["allocation_price"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's discounts for the - /// replacement price. - /// - public Generic::List? Discounts - { - get - { - if (!this.Properties.TryGetValue("discounts", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>( - element - ); - } - set { this.Properties["discounts"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The external price id of the price to add to the subscription. - /// - public string? ExternalPriceID - { - get - { - if (!this.Properties.TryGetValue("external_price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["external_price_id"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - /// - /// The new quantity of the price, if the price is a fixed price. - /// - public double? FixedPriceQuantity - { - get - { - if (!this.Properties.TryGetValue("fixed_price_quantity", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["fixed_price_quantity"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's maximum amount - /// for the replacement price. - /// - public string? MaximumAmount - { - get - { - if (!this.Properties.TryGetValue("maximum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["maximum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// [DEPRECATED] Use add_adjustments instead. The subscription's minimum amount - /// for the replacement price. - /// - public string? MinimumAmount - { - get - { - if (!this.Properties.TryGetValue("minimum_amount", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["minimum_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The definition of a new price to create and add to the subscription. - /// - public ReplacePriceProperties::Price? Price - { - get - { - if (!this.Properties.TryGetValue("price", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The id of the price to add to the subscription. - /// - public string? PriceID - { - get - { - if (!this.Properties.TryGetValue("price_id", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ReplacesPriceID; - this.AllocationPrice?.Validate(); - foreach (var item in this.Discounts ?? []) - { - item.Validate(); - } - _ = this.ExternalPriceID; - _ = this.FixedPriceQuantity; - _ = this.MaximumAmount; - _ = this.MinimumAmount; - this.Price?.Validate(); - _ = this.PriceID; - } - - public ReplacePrice() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - ReplacePrice(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static ReplacePrice FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePriceProperties/Price.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePriceProperties/Price.cs deleted file mode 100644 index 2b025006..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePriceProperties/Price.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Orb = Orb; -using PriceVariants = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplacePriceProperties.PriceVariants; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplacePriceProperties; - -/// -/// The definition of a new price to create and add to the subscription. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class Price -{ - internal Price() { } - - public static PriceVariants::NewSubscriptionUnitPrice Create( - Subscriptions::NewSubscriptionUnitPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackagePrice Create( - Subscriptions::NewSubscriptionPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixPrice Create( - Subscriptions::NewSubscriptionMatrixPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPrice Create( - Subscriptions::NewSubscriptionTieredPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredBPSPrice Create( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBPSPrice Create( - Subscriptions::NewSubscriptionBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkBPSPrice Create( - Subscriptions::NewSubscriptionBulkBPSPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkPrice Create( - Subscriptions::NewSubscriptionBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionThresholdTotalAmountPrice Create( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackagePrice Create( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithPercentPrice Create( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionPackageWithAllocationPrice Create( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTierWithProrationPrice Create( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionUnitWithProrationPrice Create( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedAllocationPrice Create( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithProratedMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionBulkWithProrationPrice Create( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithUnitPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionScalableMatrixWithTieredPricingPrice Create( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionCumulativeGroupedBulkPrice Create( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMaxGroupTieredPackagePrice Create( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedWithMeteredMinimumPrice Create( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithDisplayNamePrice Create( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPackagePrice Create( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionMatrixWithAllocationPrice Create( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionTieredPackageWithMinimumPrice Create( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) => new(value); - - public static PriceVariants::NewSubscriptionGroupedTieredPrice Create( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePriceProperties/PriceVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePriceProperties/PriceVariants/All.cs deleted file mode 100644 index 9bbca3da..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionSchedulePlanChangeParamsProperties/ReplacePriceProperties/PriceVariants/All.cs +++ /dev/null @@ -1,737 +0,0 @@ -using Orb = Orb; -using ReplacePriceProperties = Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplacePriceProperties; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; - -namespace Orb.Models.Subscriptions.SubscriptionSchedulePlanChangeParamsProperties.ReplacePriceProperties.PriceVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionUnitPrice(Subscriptions::NewSubscriptionUnitPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionUnitPrice From(Subscriptions::NewSubscriptionUnitPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackagePrice, - Subscriptions::NewSubscriptionPackagePrice - >) -)] -public sealed record class NewSubscriptionPackagePrice( - Subscriptions::NewSubscriptionPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionPackagePrice From(Subscriptions::NewSubscriptionPackagePrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixPrice, - Subscriptions::NewSubscriptionMatrixPrice - >) -)] -public sealed record class NewSubscriptionMatrixPrice( - Subscriptions::NewSubscriptionMatrixPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionMatrixPrice From(Subscriptions::NewSubscriptionMatrixPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPrice, - Subscriptions::NewSubscriptionTieredPrice - >) -)] -public sealed record class NewSubscriptionTieredPrice( - Subscriptions::NewSubscriptionTieredPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredPrice From(Subscriptions::NewSubscriptionTieredPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredBPSPrice, - Subscriptions::NewSubscriptionTieredBPSPrice - >) -)] -public sealed record class NewSubscriptionTieredBPSPrice( - Subscriptions::NewSubscriptionTieredBPSPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionTieredBPSPrice From( - Subscriptions::NewSubscriptionTieredBPSPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBPSPrice(Subscriptions::NewSubscriptionBPSPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBPSPrice From(Subscriptions::NewSubscriptionBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkBPSPrice, - Subscriptions::NewSubscriptionBulkBPSPrice - >) -)] -public sealed record class NewSubscriptionBulkBPSPrice( - Subscriptions::NewSubscriptionBulkBPSPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkBPSPrice From(Subscriptions::NewSubscriptionBulkBPSPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class NewSubscriptionBulkPrice(Subscriptions::NewSubscriptionBulkPrice Value) - : ReplacePriceProperties::Price, - Orb::IVariant -{ - public static NewSubscriptionBulkPrice From(Subscriptions::NewSubscriptionBulkPrice value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - >) -)] -public sealed record class NewSubscriptionThresholdTotalAmountPrice( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionThresholdTotalAmountPrice, - Subscriptions::NewSubscriptionThresholdTotalAmountPrice - > -{ - public static NewSubscriptionThresholdTotalAmountPrice From( - Subscriptions::NewSubscriptionThresholdTotalAmountPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionTieredPackagePrice( - Subscriptions::NewSubscriptionTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackagePrice, - Subscriptions::NewSubscriptionTieredPackagePrice - > -{ - public static NewSubscriptionTieredPackagePrice From( - Subscriptions::NewSubscriptionTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredWithMinimumPrice( - Subscriptions::NewSubscriptionTieredWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredWithMinimumPrice, - Subscriptions::NewSubscriptionTieredWithMinimumPrice - > -{ - public static NewSubscriptionTieredWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - >) -)] -public sealed record class NewSubscriptionUnitWithPercentPrice( - Subscriptions::NewSubscriptionUnitWithPercentPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithPercentPrice, - Subscriptions::NewSubscriptionUnitWithPercentPrice - > -{ - public static NewSubscriptionUnitWithPercentPrice From( - Subscriptions::NewSubscriptionUnitWithPercentPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionPackageWithAllocationPrice( - Subscriptions::NewSubscriptionPackageWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionPackageWithAllocationPrice, - Subscriptions::NewSubscriptionPackageWithAllocationPrice - > -{ - public static NewSubscriptionPackageWithAllocationPrice From( - Subscriptions::NewSubscriptionPackageWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - >) -)] -public sealed record class NewSubscriptionTierWithProrationPrice( - Subscriptions::NewSubscriptionTierWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTierWithProrationPrice, - Subscriptions::NewSubscriptionTierWithProrationPrice - > -{ - public static NewSubscriptionTierWithProrationPrice From( - Subscriptions::NewSubscriptionTierWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - >) -)] -public sealed record class NewSubscriptionUnitWithProrationPrice( - Subscriptions::NewSubscriptionUnitWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionUnitWithProrationPrice, - Subscriptions::NewSubscriptionUnitWithProrationPrice - > -{ - public static NewSubscriptionUnitWithProrationPrice From( - Subscriptions::NewSubscriptionUnitWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - >) -)] -public sealed record class NewSubscriptionGroupedAllocationPrice( - Subscriptions::NewSubscriptionGroupedAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedAllocationPrice, - Subscriptions::NewSubscriptionGroupedAllocationPrice - > -{ - public static NewSubscriptionGroupedAllocationPrice From( - Subscriptions::NewSubscriptionGroupedAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithProratedMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithProratedMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice - > -{ - public static NewSubscriptionGroupedWithProratedMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithProratedMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - >) -)] -public sealed record class NewSubscriptionBulkWithProrationPrice( - Subscriptions::NewSubscriptionBulkWithProrationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionBulkWithProrationPrice, - Subscriptions::NewSubscriptionBulkWithProrationPrice - > -{ - public static NewSubscriptionBulkWithProrationPrice From( - Subscriptions::NewSubscriptionBulkWithProrationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithUnitPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithUnitPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithUnitPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithUnitPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - >) -)] -public sealed record class NewSubscriptionScalableMatrixWithTieredPricingPrice( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionScalableMatrixWithTieredPricingPrice, - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice - > -{ - public static NewSubscriptionScalableMatrixWithTieredPricingPrice From( - Subscriptions::NewSubscriptionScalableMatrixWithTieredPricingPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - >) -)] -public sealed record class NewSubscriptionCumulativeGroupedBulkPrice( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionCumulativeGroupedBulkPrice, - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice - > -{ - public static NewSubscriptionCumulativeGroupedBulkPrice From( - Subscriptions::NewSubscriptionCumulativeGroupedBulkPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionMaxGroupTieredPackagePrice( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionMaxGroupTieredPackagePrice, - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice - > -{ - public static NewSubscriptionMaxGroupTieredPackagePrice From( - Subscriptions::NewSubscriptionMaxGroupTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - >) -)] -public sealed record class NewSubscriptionGroupedWithMeteredMinimumPrice( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedWithMeteredMinimumPrice, - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice - > -{ - public static NewSubscriptionGroupedWithMeteredMinimumPrice From( - Subscriptions::NewSubscriptionGroupedWithMeteredMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - >) -)] -public sealed record class NewSubscriptionMatrixWithDisplayNamePrice( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithDisplayNamePrice, - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice - > -{ - public static NewSubscriptionMatrixWithDisplayNamePrice From( - Subscriptions::NewSubscriptionMatrixWithDisplayNamePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPackagePrice( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPackagePrice, - Subscriptions::NewSubscriptionGroupedTieredPackagePrice - > -{ - public static NewSubscriptionGroupedTieredPackagePrice From( - Subscriptions::NewSubscriptionGroupedTieredPackagePrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - >) -)] -public sealed record class NewSubscriptionMatrixWithAllocationPrice( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionMatrixWithAllocationPrice, - Subscriptions::NewSubscriptionMatrixWithAllocationPrice - > -{ - public static NewSubscriptionMatrixWithAllocationPrice From( - Subscriptions::NewSubscriptionMatrixWithAllocationPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - >) -)] -public sealed record class NewSubscriptionTieredPackageWithMinimumPrice( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionTieredPackageWithMinimumPrice, - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice - > -{ - public static NewSubscriptionTieredPackageWithMinimumPrice From( - Subscriptions::NewSubscriptionTieredPackageWithMinimumPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - >) -)] -public sealed record class NewSubscriptionGroupedTieredPrice( - Subscriptions::NewSubscriptionGroupedTieredPrice Value -) - : ReplacePriceProperties::Price, - Orb::IVariant< - NewSubscriptionGroupedTieredPrice, - Subscriptions::NewSubscriptionGroupedTieredPrice - > -{ - public static NewSubscriptionGroupedTieredPrice From( - Subscriptions::NewSubscriptionGroupedTieredPrice value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionSubscriptions.cs b/src/Orb/Models/Subscriptions/SubscriptionSubscriptions.cs new file mode 100644 index 00000000..31d21af9 --- /dev/null +++ b/src/Orb/Models/Subscriptions/SubscriptionSubscriptions.cs @@ -0,0 +1,76 @@ +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; + +namespace Orb.Models.Subscriptions; + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class SubscriptionSubscriptions : JsonModel +{ + public required IReadOnlyList Data + { + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } + } + + public required PaginationMetadata PaginationMetadata + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "pagination_metadata" + ); + } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Data) + { + item.Validate(); + } + this.PaginationMetadata.Validate(); + } + + public SubscriptionSubscriptions() { } + + public SubscriptionSubscriptions(SubscriptionSubscriptions subscriptionSubscriptions) + : base(subscriptionSubscriptions) { } + + public SubscriptionSubscriptions(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionSubscriptions(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionSubscriptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SubscriptionSubscriptionsFromRaw : IFromRawJson +{ + /// + public SubscriptionSubscriptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SubscriptionSubscriptions.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionTriggerPhaseParams.cs b/src/Orb/Models/Subscriptions/SubscriptionTriggerPhaseParams.cs index b4e23106..fe144c7f 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionTriggerPhaseParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionTriggerPhaseParams.cs @@ -1,20 +1,26 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; /// /// Manually trigger a phase, effective the given date (or the current time, if not specified). /// -public sealed record class SubscriptionTriggerPhaseParams : Orb::ParamsBase +public sealed record class SubscriptionTriggerPhaseParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// If false, this request will fail if it would void an issued invoice or create @@ -25,68 +31,99 @@ public bool? AllowInvoiceCreditOrVoid { get { - if ( - !this.BodyProperties.TryGetValue( - "allow_invoice_credit_or_void", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["allow_invoice_credit_or_void"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "allow_invoice_credit_or_void" + ); } + init { JsonModel.Set(this._rawBodyData, "allow_invoice_credit_or_void", value); } } /// /// The date on which the phase change should take effect. If not provided, defaults /// to today in the customer's timezone. /// - public System::DateOnly? EffectiveDate + public string? EffectiveDate { - get - { - if (!this.BodyProperties.TryGetValue("effective_date", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "effective_date"); } + init { JsonModel.Set(this._rawBodyData, "effective_date", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); - } + public SubscriptionTriggerPhaseParams() { } + + public SubscriptionTriggerPhaseParams( + SubscriptionTriggerPhaseParams subscriptionTriggerPhaseParams + ) + : base(subscriptionTriggerPhaseParams) + { + this._rawBodyData = [.. subscriptionTriggerPhaseParams._rawBodyData]; + } + + public SubscriptionTriggerPhaseParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionTriggerPhaseParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionTriggerPhaseParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/trigger_phase", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUnscheduleCancellationParams.cs b/src/Orb/Models/Subscriptions/SubscriptionUnscheduleCancellationParams.cs index 11120afc..0a342635 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUnscheduleCancellationParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUnscheduleCancellationParams.cs @@ -1,37 +1,81 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; /// /// This endpoint can be used to unschedule any pending cancellations for a subscription. /// -/// To be eligible, the subscription must currently be active and have a future cancellation. -/// This operation will turn on auto-renew, ensuring that the subscription does not -/// end at the currently scheduled cancellation time. +/// To be eligible, the subscription must currently be active and have a future +/// cancellation. This operation will turn on auto-renew, ensuring that the subscription +/// does not end at the currently scheduled cancellation time. /// -public sealed record class SubscriptionUnscheduleCancellationParams : Orb::ParamsBase +public sealed record class SubscriptionUnscheduleCancellationParams : ParamsBase { - public required string SubscriptionID; + public string? SubscriptionID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionUnscheduleCancellationParams() { } + + public SubscriptionUnscheduleCancellationParams( + SubscriptionUnscheduleCancellationParams subscriptionUnscheduleCancellationParams + ) + : base(subscriptionUnscheduleCancellationParams) { } + + public SubscriptionUnscheduleCancellationParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionUnscheduleCancellationParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionUnscheduleCancellationParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/unschedule_cancellation", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParams.cs b/src/Orb/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParams.cs index da2c8ccb..2de0a808 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUnscheduleFixedFeeQuantityUpdatesParams.cs @@ -1,72 +1,117 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; /// /// This endpoint can be used to clear scheduled updates to the quantity for a fixed fee. /// -/// If there are no updates scheduled, a request validation error will be returned -/// with a 400 status code. +/// If there are no updates scheduled, a request validation error will be returned +/// with a 400 status code. /// -public sealed record class SubscriptionUnscheduleFixedFeeQuantityUpdatesParams : Orb::ParamsBase +public sealed record class SubscriptionUnscheduleFixedFeeQuantityUpdatesParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// Price for which the updates should be cleared. Must be a fixed fee. /// public required string PriceID { - get - { - if (!this.BodyProperties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); + get { return JsonModel.GetNotNullClass(this.RawBodyData, "price_id"); } + init { JsonModel.Set(this._rawBodyData, "price_id", value); } + } - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.BodyProperties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } + public SubscriptionUnscheduleFixedFeeQuantityUpdatesParams() { } + + public SubscriptionUnscheduleFixedFeeQuantityUpdatesParams( + SubscriptionUnscheduleFixedFeeQuantityUpdatesParams subscriptionUnscheduleFixedFeeQuantityUpdatesParams + ) + : base(subscriptionUnscheduleFixedFeeQuantityUpdatesParams) + { + this._rawBodyData = [.. subscriptionUnscheduleFixedFeeQuantityUpdatesParams._rawBodyData]; + } + + public SubscriptionUnscheduleFixedFeeQuantityUpdatesParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionUnscheduleFixedFeeQuantityUpdatesParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionUnscheduleFixedFeeQuantityUpdatesParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/subscriptions/{0}/unschedule_fixed_fee_quantity_updates", this.SubscriptionID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParams.cs b/src/Orb/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParams.cs index 19693776..69704648 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUnschedulePendingPlanChangesParams.cs @@ -1,6 +1,10 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; @@ -8,30 +12,70 @@ namespace Orb.Models.Subscriptions; /// This endpoint can be used to unschedule any pending plan changes on an existing /// subscription. When called, all upcoming plan changes will be unscheduled. /// -public sealed record class SubscriptionUnschedulePendingPlanChangesParams : Orb::ParamsBase +public sealed record class SubscriptionUnschedulePendingPlanChangesParams : ParamsBase { - public required string SubscriptionID; + public string? SubscriptionID { get; init; } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionUnschedulePendingPlanChangesParams() { } + + public SubscriptionUnschedulePendingPlanChangesParams( + SubscriptionUnschedulePendingPlanChangesParams subscriptionUnschedulePendingPlanChangesParams + ) + : base(subscriptionUnschedulePendingPlanChangesParams) { } + + public SubscriptionUnschedulePendingPlanChangesParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionUnschedulePendingPlanChangesParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionUnschedulePendingPlanChangesParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format( "/subscriptions/{0}/unschedule_pending_plan_changes", this.SubscriptionID ) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParams.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParams.cs index 8d6660ce..00c63742 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParams.cs @@ -1,65 +1,53 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionUpdateFixedFeeQuantityParamsProperties = Orb.Models.Subscriptions.SubscriptionUpdateFixedFeeQuantityParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; /// /// This endpoint can be used to update the quantity for a fixed fee. /// -/// To be eligible, the subscription must currently be active and the price specified -/// must be a fixed fee (not usage-based). This operation will immediately update -/// the quantity for the fee, or if a `effective_date` is passed in, will update -/// the quantity on the requested date at midnight in the customer's timezone. +/// To be eligible, the subscription must currently be active and the price +/// specified must be a fixed fee (not usage-based). This operation will immediately +/// update the quantity for the fee, or if a `effective_date` is passed in, will +/// update the quantity on the requested date at midnight in the customer's timezone. /// -/// In order to change the fixed fee quantity as of the next draft invoice for this -/// subscription, pass `change_option=upcoming_invoice` without an `effective_date` specified. +/// In order to change the fixed fee quantity as of the next draft invoice +/// for this subscription, pass `change_option=upcoming_invoice` without an `effective_date` specified. /// -/// If the fee is an in-advance fixed fee, it will also issue an immediate invoice -/// for the difference for the remainder of the billing period. +/// If the fee is an in-advance fixed fee, it will also issue an immediate +/// invoice for the difference for the remainder of the billing period. /// -public sealed record class SubscriptionUpdateFixedFeeQuantityParams : Orb::ParamsBase +public sealed record class SubscriptionUpdateFixedFeeQuantityParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// Price for which the quantity should be updated. Must be a fixed fee. /// public required string PriceID { - get - { - if (!this.BodyProperties.TryGetValue("price_id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "price_id", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("price_id"); - } - set { this.BodyProperties["price_id"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "price_id"); } + init { JsonModel.Set(this._rawBodyData, "price_id", value); } } public required double Quantity { - get - { - if (!this.BodyProperties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawBodyData, "quantity"); } + init { JsonModel.Set(this._rawBodyData, "quantity", value); } } /// @@ -71,42 +59,35 @@ public bool? AllowInvoiceCreditOrVoid { get { - if ( - !this.BodyProperties.TryGetValue( - "allow_invoice_credit_or_void", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["allow_invoice_credit_or_void"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNullableStruct( + this.RawBodyData, + "allow_invoice_credit_or_void" + ); } + init { JsonModel.Set(this._rawBodyData, "allow_invoice_credit_or_void", value); } } /// - /// Determines when the change takes effect. Note that if `effective_date` is specified, - /// this defaults to `effective_date`. Otherwise, this defaults to `immediate` - /// unless it's explicitly set to `upcoming_invoice`. + /// Determines when the change takes effect. Note that if `effective_date` is + /// specified, this defaults to `effective_date`. Otherwise, this defaults to + /// `immediate` unless it's explicitly set to `upcoming_invoice`. /// - public SubscriptionUpdateFixedFeeQuantityParamsProperties::ChangeOption? ChangeOption + public ApiEnum? ChangeOption { get { - if (!this.BodyProperties.TryGetValue("change_option", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize( - element - ); + return JsonModel.GetNullableClass< + ApiEnum + >(this.RawBodyData, "change_option"); } - set + init { - this.BodyProperties["change_option"] = Json::JsonSerializer.SerializeToElement(value); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawBodyData, "change_option", value); } } @@ -115,47 +96,143 @@ public bool? AllowInvoiceCreditOrVoid /// timezone. If this parameter is not passed in, the quantity change is effective /// according to `change_option`. /// - public System::DateOnly? EffectiveDate + public string? EffectiveDate { - get - { - if (!this.BodyProperties.TryGetValue("effective_date", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableClass(this.RawBodyData, "effective_date"); } + init { JsonModel.Set(this._rawBodyData, "effective_date", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["effective_date"] = Json::JsonSerializer.SerializeToElement(value); - } + public SubscriptionUpdateFixedFeeQuantityParams() { } + + public SubscriptionUpdateFixedFeeQuantityParams( + SubscriptionUpdateFixedFeeQuantityParams subscriptionUpdateFixedFeeQuantityParams + ) + : base(subscriptionUpdateFixedFeeQuantityParams) + { + this._rawBodyData = [.. subscriptionUpdateFixedFeeQuantityParams._rawBodyData]; } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionUpdateFixedFeeQuantityParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionUpdateFixedFeeQuantityParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionUpdateFixedFeeQuantityParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/update_fixed_fee_quantity", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } + +/// +/// Determines when the change takes effect. Note that if `effective_date` is specified, +/// this defaults to `effective_date`. Otherwise, this defaults to `immediate` unless +/// it's explicitly set to `upcoming_invoice`. +/// +[JsonConverter(typeof(SubscriptionUpdateFixedFeeQuantityParamsChangeOptionConverter))] +public enum SubscriptionUpdateFixedFeeQuantityParamsChangeOption +{ + Immediate, + UpcomingInvoice, + EffectiveDate, +} + +sealed class SubscriptionUpdateFixedFeeQuantityParamsChangeOptionConverter + : JsonConverter +{ + public override SubscriptionUpdateFixedFeeQuantityParamsChangeOption Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "immediate" => SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate, + "upcoming_invoice" => + SubscriptionUpdateFixedFeeQuantityParamsChangeOption.UpcomingInvoice, + "effective_date" => SubscriptionUpdateFixedFeeQuantityParamsChangeOption.EffectiveDate, + _ => (SubscriptionUpdateFixedFeeQuantityParamsChangeOption)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionUpdateFixedFeeQuantityParamsChangeOption value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SubscriptionUpdateFixedFeeQuantityParamsChangeOption.Immediate => "immediate", + SubscriptionUpdateFixedFeeQuantityParamsChangeOption.UpcomingInvoice => + "upcoming_invoice", + SubscriptionUpdateFixedFeeQuantityParamsChangeOption.EffectiveDate => + "effective_date", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParamsProperties/ChangeOption.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParamsProperties/ChangeOption.cs deleted file mode 100644 index 431e3fbc..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateFixedFeeQuantityParamsProperties/ChangeOption.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUpdateFixedFeeQuantityParamsProperties; - -/// -/// Determines when the change takes effect. Note that if `effective_date` is specified, -/// this defaults to `effective_date`. Otherwise, this defaults to `immediate` unless -/// it's explicitly set to `upcoming_invoice`. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ChangeOption(string value) : Orb::IEnum -{ - public static readonly ChangeOption Immediate = new("immediate"); - - public static readonly ChangeOption UpcomingInvoice = new("upcoming_invoice"); - - public static readonly ChangeOption EffectiveDate = new("effective_date"); - - readonly string _value = value; - - public enum Value - { - Immediate, - UpcomingInvoice, - EffectiveDate, - } - - public Value Known() => - _value switch - { - "immediate" => Value.Immediate, - "upcoming_invoice" => Value.UpcomingInvoice, - "effective_date" => Value.EffectiveDate, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ChangeOption FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateParams.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateParams.cs index 936279c1..c8e05576 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUpdateParams.cs @@ -1,9 +1,11 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Text = System.Text; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.Subscriptions; @@ -11,11 +13,15 @@ namespace Orb.Models.Subscriptions; /// This endpoint can be used to update the `metadata`, `net terms`, `auto_collection`, /// `invoicing_threshold`, and `default_invoice_memo` properties on a subscription. /// -public sealed record class SubscriptionUpdateParams : Orb::ParamsBase +public sealed record class SubscriptionUpdateParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// /// Determines whether issued invoices for this subscription will automatically @@ -24,70 +30,29 @@ public sealed record class SubscriptionUpdateParams : Orb::ParamsBase /// public bool? AutoCollection { - get - { - if (!this.BodyProperties.TryGetValue("auto_collection", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["auto_collection"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableStruct(this.RawBodyData, "auto_collection"); } + init { JsonModel.Set(this._rawBodyData, "auto_collection", value); } } /// - /// Determines the default memo on this subscription's invoices. Note that if this - /// is not provided, it is determined by the plan configuration. + /// Determines the default memo on this subscription's invoices. Note that if + /// this is not provided, it is determined by the plan configuration. /// public string? DefaultInvoiceMemo { - get - { - if ( - !this.BodyProperties.TryGetValue( - "default_invoice_memo", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["default_invoice_memo"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "default_invoice_memo"); } + init { JsonModel.Set(this._rawBodyData, "default_invoice_memo", value); } } /// - /// When this subscription's accrued usage reaches this threshold, an invoice will - /// be issued for the subscription. If not specified, invoices will only be issued - /// at the end of the billing period. + /// When this subscription's accrued usage reaches this threshold, an invoice + /// will be issued for the subscription. If not specified, invoices will only + /// be issued at the end of the billing period. /// public string? InvoicingThreshold { - get - { - if ( - !this.BodyProperties.TryGetValue( - "invoicing_threshold", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.BodyProperties["invoicing_threshold"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawBodyData, "invoicing_threshold"); } + init { JsonModel.Set(this._rawBodyData, "invoicing_threshold", value); } } /// @@ -95,62 +60,103 @@ public string? InvoicingThreshold /// by setting the value to `null`, and the entire metadata mapping can be cleared /// by setting `metadata` to `null`. /// - public Generic::Dictionary? Metadata + public IReadOnlyDictionary? Metadata { get { - if (!this.BodyProperties.TryGetValue("metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>( + this.RawBodyData, + "metadata" + ); } - set { this.BodyProperties["metadata"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawBodyData, "metadata", value); } } /// - /// Determines the difference between the invoice issue date for subscription invoices - /// as the date that they are due. A value of `0` here represents that the invoice - /// is due on issue, whereas a value of `30` represents that the customer has a - /// month to pay the invoice. + /// Determines the difference between the invoice issue date for subscription + /// invoices as the date that they are due. A value of `0` here represents that + /// the invoice is due on issue, whereas a value of `30` represents that the customer + /// has a month to pay the invoice. /// public long? NetTerms { - get - { - if (!this.BodyProperties.TryGetValue("net_terms", out Json::JsonElement element)) - return null; + get { return JsonModel.GetNullableStruct(this.RawBodyData, "net_terms"); } + init { JsonModel.Set(this._rawBodyData, "net_terms", value); } + } - return Json::JsonSerializer.Deserialize(element); - } - set { this.BodyProperties["net_terms"] = Json::JsonSerializer.SerializeToElement(value); } + public SubscriptionUpdateParams() { } + + public SubscriptionUpdateParams(SubscriptionUpdateParams subscriptionUpdateParams) + : base(subscriptionUpdateParams) + { + this._rawBodyData = [.. subscriptionUpdateParams._rawBodyData]; + } + + public SubscriptionUpdateParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionUpdateParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionUpdateParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); } - public override System::Uri Url(Orb::IOrbClient client) + public override Uri Url(ClientOptions options) { - return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + return new UriBuilder( + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParams.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParams.cs index e19d50cb..1091e591 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParams.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParams.cs @@ -1,10 +1,13 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionUpdateTrialParamsProperties = Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using Text = System.Text; namespace Orb.Models.Subscriptions; @@ -14,46 +17,38 @@ namespace Orb.Models.Subscriptions; /// trial end date must be on or after the subscription's start date on the current /// plan, and on or before the subscription end date). /// -/// In order to retroactively remove a trial completely, the end date can be set to -/// the transition date of the subscription to this plan (or, if this is the first -/// plan for this subscription, the subscription's start date). In order to end a -/// trial immediately, the keyword `immediate` can be provided as the trial end date. +/// In order to retroactively remove a trial completely, the end date can be +/// set to the transition date of the subscription to this plan (or, if this is the +/// first plan for this subscription, the subscription's start date). In order to +/// end a trial immediately, the keyword `immediate` can be provided as the trial +/// end date. /// -/// By default, Orb will shift only the trial end date (and price intervals that start -/// or end on the previous trial end date), and leave all other future price intervals -/// untouched. If the `shift` parameter is set to `true`, Orb will shift all subsequent -/// price and adjustment intervals by the same amount as the trial end date shift -/// (so, e.g., if a plan change is scheduled or an add-on price was added, that change -/// will be pushed back by the same amount of time the trial is extended). +/// By default, Orb will shift only the trial end date (and price intervals +/// that start or end on the previous trial end date), and leave all other future +/// price intervals untouched. If the `shift` parameter is set to `true`, Orb will +/// shift all subsequent price and adjustment intervals by the same amount as the +/// trial end date shift (so, e.g., if a plan change is scheduled or an add-on price +/// was added, that change will be pushed back by the same amount of time the trial +/// is extended). /// -public sealed record class SubscriptionUpdateTrialParams : Orb::ParamsBase +public sealed record class SubscriptionUpdateTrialParams : ParamsBase { - public Generic::Dictionary BodyProperties { get; set; } = []; + readonly FreezableDictionary _rawBodyData = []; + public IReadOnlyDictionary RawBodyData + { + get { return this._rawBodyData.Freeze(); } + } - public required string SubscriptionID; + public string? SubscriptionID { get; init; } /// - /// The new date that the trial should end, or the literal string `immediate` to - /// end the trial immediately. + /// The new date that the trial should end, or the literal string `immediate` + /// to end the trial immediately. /// - public required SubscriptionUpdateTrialParamsProperties::TrialEndDate TrialEndDate + public required TrialEndDate TrialEndDate { - get - { - if (!this.BodyProperties.TryGetValue("trial_end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "trial_end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("trial_end_date"); - } - set - { - this.BodyProperties["trial_end_date"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNotNullClass(this.RawBodyData, "trial_end_date"); } + init { JsonModel.Set(this._rawBodyData, "trial_end_date", value); } } /// @@ -62,42 +57,367 @@ public sealed record class SubscriptionUpdateTrialParams : Orb::ParamsBase /// public bool? Shift { - get + get { return JsonModel.GetNullableStruct(this.RawBodyData, "shift"); } + init { - if (!this.BodyProperties.TryGetValue("shift", out Json::JsonElement element)) - return null; + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize(element); + JsonModel.Set(this._rawBodyData, "shift", value); } - set { this.BodyProperties["shift"] = Json::JsonSerializer.SerializeToElement(value); } } - public override System::Uri Url(Orb::IOrbClient client) + public SubscriptionUpdateTrialParams() { } + + public SubscriptionUpdateTrialParams( + SubscriptionUpdateTrialParams subscriptionUpdateTrialParams + ) + : base(subscriptionUpdateTrialParams) + { + this._rawBodyData = [.. subscriptionUpdateTrialParams._rawBodyData]; + } + + public SubscriptionUpdateTrialParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SubscriptionUpdateTrialParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData, + FrozenDictionary rawBodyData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + this._rawBodyData = [.. rawBodyData]; + } +#pragma warning restore CS8618 + + /// + public static SubscriptionUpdateTrialParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData, + IReadOnlyDictionary rawBodyData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData), + FrozenDictionary.ToFrozenDictionary(rawBodyData) + ); + } + + public override System::Uri Url(ClientOptions options) { return new System::UriBuilder( - client.BaseUrl.ToString().TrimEnd('/') + options.BaseUrl.ToString().TrimEnd('/') + string.Format("/subscriptions/{0}/update_trial", this.SubscriptionID) ) { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public Http::StringContent BodyContent() + internal override HttpContent? BodyContent() { - return new Http::StringContent( - Json::JsonSerializer.Serialize(this.BodyProperties), - Text::Encoding.UTF8, + return new StringContent( + JsonSerializer.Serialize(this.RawBodyData), + Encoding.UTF8, "application/json" ); } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) + { + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) + { + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + } + } +} + +/// +/// The new date that the trial should end, or the literal string `immediate` to +/// end the trial immediately. +/// +[JsonConverter(typeof(TrialEndDateConverter))] +public record class TrialEndDate +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } + + public TrialEndDate(System::DateTimeOffset value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TrialEndDate(ApiEnum value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public TrialEndDate(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickDateTimeOffset(out var value)) { + /// // `value` is of type `System::DateTimeOffset` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickDateTimeOffset([NotNullWhen(true)] out System::DateTimeOffset? value) + { + value = this.Value as System::DateTimeOffset?; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUnionMember1(out var value)) { + /// // `value` is of type `ApiEnum` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUnionMember1([NotNullWhen(true)] out ApiEnum? value) + { + value = this.Value as ApiEnum; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action @dateTimeOffset, + System::Action> unionMember1 + ) + { + switch (this.Value) + { + case System::DateTimeOffset value: + @dateTimeOffset(value); + break; + case ApiEnum value: + unionMember1(value); + break; + default: + throw new OrbInvalidDataException("Data did not match any variant of TrialEndDate"); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (System::DateTimeOffset value) => {...}, + /// (ApiEnum value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func @dateTimeOffset, + System::Func, T> unionMember1 + ) + { + return this.Value switch + { + System::DateTimeOffset value => @dateTimeOffset(value), + ApiEnum value => unionMember1(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of TrialEndDate" + ), + }; + } + + public static implicit operator TrialEndDate(System::DateTimeOffset value) => new(value); + + public static implicit operator TrialEndDate(ApiEnum value) => new(value); + + public static implicit operator TrialEndDate(UnionMember1 value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException("Data did not match any variant of TrialEndDate"); + } + this.Switch((_) => { }, (unionMember1) => unionMember1.Validate()); + } + + public virtual bool Equals(TrialEndDate? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class TrialEndDateConverter : JsonConverter +{ + public override TrialEndDate? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize>( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + return new(JsonSerializer.Deserialize(element, options)); + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + // ignore } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + TrialEndDate value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter(typeof(UnionMember1Converter))] +public enum UnionMember1 +{ + Immediate, +} + +sealed class UnionMember1Converter : JsonConverter +{ + public override UnionMember1 Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "immediate" => UnionMember1.Immediate, + _ => (UnionMember1)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UnionMember1 value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UnionMember1.Immediate => "immediate", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDate.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDate.cs deleted file mode 100644 index f2a3d26a..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TrialEndDateProperties = Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties.TrialEndDateProperties; -using TrialEndDateVariants = Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties.TrialEndDateVariants; - -namespace Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties; - -/// -/// The new date that the trial should end, or the literal string `immediate` to end -/// the trial immediately. -/// -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class TrialEndDate -{ - internal TrialEndDate() { } - - public static TrialEndDateVariants::UnionMember0 Create(System::DateTime value) => new(value); - - public static TrialEndDateVariants::UnionMember1 Create( - TrialEndDateProperties::UnionMember1 value - ) => new(value); - - public abstract void Validate(); -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDateProperties/UnionMember1.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDateProperties/UnionMember1.cs deleted file mode 100644 index 65de54b9..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDateProperties/UnionMember1.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties.TrialEndDateProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class UnionMember1(string value) : Orb::IEnum -{ - public static readonly UnionMember1 Immediate = new("immediate"); - - readonly string _value = value; - - public enum Value - { - Immediate, - } - - public Value Known() => - _value switch - { - "immediate" => Value.Immediate, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static UnionMember1 FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDateVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDateVariants/All.cs deleted file mode 100644 index 0dd0c8f0..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUpdateTrialParamsProperties/TrialEndDateVariants/All.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionUpdateTrialParamsProperties = Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties; -using System = System; -using TrialEndDateProperties = Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties.TrialEndDateProperties; - -namespace Orb.Models.Subscriptions.SubscriptionUpdateTrialParamsProperties.TrialEndDateVariants; - -[Serialization::JsonConverter(typeof(Orb::VariantConverter))] -public sealed record class UnionMember0(System::DateTime Value) - : SubscriptionUpdateTrialParamsProperties::TrialEndDate, - Orb::IVariant -{ - public static UnionMember0 From(System::DateTime value) - { - return new(value); - } - - public override void Validate() { } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter) -)] -public sealed record class UnionMember1(TrialEndDateProperties::UnionMember1 Value) - : SubscriptionUpdateTrialParamsProperties::TrialEndDate, - Orb::IVariant -{ - public static UnionMember1 From(TrialEndDateProperties::UnionMember1 value) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsage.cs b/src/Orb/Models/Subscriptions/SubscriptionUsage.cs index 737f0876..3de61848 100644 --- a/src/Orb/Models/Subscriptions/SubscriptionUsage.cs +++ b/src/Orb/Models/Subscriptions/SubscriptionUsage.cs @@ -1,22 +1,977 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using SubscriptionUsageProperties = Orb.Models.Subscriptions.SubscriptionUsageProperties; -using SubscriptionUsageVariants = Orb.Models.Subscriptions.SubscriptionUsageVariants; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; +using System = System; namespace Orb.Models.Subscriptions; -[Serialization::JsonConverter(typeof(Orb::UnionConverter))] -public abstract record class SubscriptionUsage +[JsonConverter(typeof(SubscriptionUsageConverter))] +public record class SubscriptionUsage { - internal SubscriptionUsage() { } + public object? Value { get; } = null; - public static SubscriptionUsageVariants::UngroupedSubscriptionUsage Create( - SubscriptionUsageProperties::UngroupedSubscriptionUsage value - ) => new(value); + JsonElement? _element = null; - public static SubscriptionUsageVariants::GroupedSubscriptionUsage Create( - SubscriptionUsageProperties::GroupedSubscriptionUsage value - ) => new(value); + public JsonElement Json + { + get { return this._element ??= JsonSerializer.SerializeToElement(this.Value); } + } - public abstract void Validate(); + public SubscriptionUsage(UngroupedSubscriptionUsage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubscriptionUsage(GroupedSubscriptionUsage value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public SubscriptionUsage(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickUngrouped(out var value)) { + /// // `value` is of type `UngroupedSubscriptionUsage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickUngrouped([NotNullWhen(true)] out UngroupedSubscriptionUsage? value) + { + value = this.Value as UngroupedSubscriptionUsage; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGrouped(out var value)) { + /// // `value` is of type `GroupedSubscriptionUsage` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGrouped([NotNullWhen(true)] out GroupedSubscriptionUsage? value) + { + value = this.Value as GroupedSubscriptionUsage; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (UngroupedSubscriptionUsage value) => {...}, + /// (GroupedSubscriptionUsage value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action ungrouped, + System::Action grouped + ) + { + switch (this.Value) + { + case UngroupedSubscriptionUsage value: + ungrouped(value); + break; + case GroupedSubscriptionUsage value: + grouped(value); + break; + default: + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionUsage" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (UngroupedSubscriptionUsage value) => {...}, + /// (GroupedSubscriptionUsage value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func ungrouped, + System::Func grouped + ) + { + return this.Value switch + { + UngroupedSubscriptionUsage value => ungrouped(value), + GroupedSubscriptionUsage value => grouped(value), + _ => throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionUsage" + ), + }; + } + + public static implicit operator SubscriptionUsage(UngroupedSubscriptionUsage value) => + new(value); + + public static implicit operator SubscriptionUsage(GroupedSubscriptionUsage value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public void Validate() + { + if (this.Value == null) + { + throw new OrbInvalidDataException( + "Data did not match any variant of SubscriptionUsage" + ); + } + this.Switch((ungrouped) => ungrouped.Validate(), (grouped) => grouped.Validate()); + } + + public virtual bool Equals(SubscriptionUsage? other) + { + return other != null && JsonElement.DeepEquals(this.Json, other.Json); + } + + public override int GetHashCode() + { + return 0; + } +} + +sealed class SubscriptionUsageConverter : JsonConverter +{ + public override SubscriptionUsage? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is OrbInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + SubscriptionUsage value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class UngroupedSubscriptionUsage : JsonModel +{ + public required IReadOnlyList Data + { + get { return JsonModel.GetNotNullClass>(this.RawData, "data"); } + init { JsonModel.Set(this._rawData, "data", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Data) + { + item.Validate(); + } + } + + public UngroupedSubscriptionUsage() { } + + public UngroupedSubscriptionUsage(UngroupedSubscriptionUsage ungroupedSubscriptionUsage) + : base(ungroupedSubscriptionUsage) { } + + public UngroupedSubscriptionUsage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UngroupedSubscriptionUsage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UngroupedSubscriptionUsage FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public UngroupedSubscriptionUsage(List data) + : this() + { + this.Data = data; + } +} + +class UngroupedSubscriptionUsageFromRaw : IFromRawJson +{ + /// + public UngroupedSubscriptionUsage FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UngroupedSubscriptionUsage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Data : JsonModel +{ + public required BillableMetric BillableMetric + { + get { return JsonModel.GetNotNullClass(this.RawData, "billable_metric"); } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required IReadOnlyList Usage + { + get { return JsonModel.GetNotNullClass>(this.RawData, "usage"); } + init { JsonModel.Set(this._rawData, "usage", value); } + } + + public required ApiEnum ViewMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "view_mode" + ); + } + init { JsonModel.Set(this._rawData, "view_mode", value); } + } + + /// + public override void Validate() + { + this.BillableMetric.Validate(); + foreach (var item in this.Usage) + { + item.Validate(); + } + this.ViewMode.Validate(); + } + + public Data() { } + + public Data(Data data) + : base(data) { } + + public Data(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Data(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static Data FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DataFromRaw : IFromRawJson +{ + /// + public Data FromRawUnchecked(IReadOnlyDictionary rawData) => + Data.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class BillableMetric : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Name; + } + + public BillableMetric() { } + + public BillableMetric(BillableMetric billableMetric) + : base(billableMetric) { } + + public BillableMetric(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + BillableMetric(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static BillableMetric FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class BillableMetricFromRaw : IFromRawJson +{ + /// + public BillableMetric FromRawUnchecked(IReadOnlyDictionary rawData) => + BillableMetric.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class DataUsage : JsonModel +{ + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + public required System::DateTimeOffset TimeframeEnd + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); + } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } + } + + public required System::DateTimeOffset TimeframeStart + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); + } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } + } + + /// + public override void Validate() + { + _ = this.Quantity; + _ = this.TimeframeEnd; + _ = this.TimeframeStart; + } + + public DataUsage() { } + + public DataUsage(DataUsage dataUsage) + : base(dataUsage) { } + + public DataUsage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + DataUsage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static DataUsage FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class DataUsageFromRaw : IFromRawJson +{ + /// + public DataUsage FromRawUnchecked(IReadOnlyDictionary rawData) => + DataUsage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(DataViewModeConverter))] +public enum DataViewMode +{ + Periodic, + Cumulative, +} + +sealed class DataViewModeConverter : JsonConverter +{ + public override DataViewMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "periodic" => DataViewMode.Periodic, + "cumulative" => DataViewMode.Cumulative, + _ => (DataViewMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + DataViewMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + DataViewMode.Periodic => "periodic", + DataViewMode.Cumulative => "cumulative", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class GroupedSubscriptionUsage : JsonModel +{ + public required IReadOnlyList Data + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "data" + ); + } + init { JsonModel.Set(this._rawData, "data", value); } + } + + public PaginationMetadata? PaginationMetadata + { + get + { + return JsonModel.GetNullableClass( + this.RawData, + "pagination_metadata" + ); + } + init { JsonModel.Set(this._rawData, "pagination_metadata", value); } + } + + /// + public override void Validate() + { + foreach (var item in this.Data) + { + item.Validate(); + } + this.PaginationMetadata?.Validate(); + } + + public GroupedSubscriptionUsage() { } + + public GroupedSubscriptionUsage(GroupedSubscriptionUsage groupedSubscriptionUsage) + : base(groupedSubscriptionUsage) { } + + public GroupedSubscriptionUsage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedSubscriptionUsage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedSubscriptionUsage FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public GroupedSubscriptionUsage(List data) + : this() + { + this.Data = data; + } +} + +class GroupedSubscriptionUsageFromRaw : IFromRawJson +{ + /// + public GroupedSubscriptionUsage FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedSubscriptionUsage.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class GroupedSubscriptionUsageData : JsonModel +{ + public required GroupedSubscriptionUsageDataBillableMetric BillableMetric + { + get + { + return JsonModel.GetNotNullClass( + this.RawData, + "billable_metric" + ); + } + init { JsonModel.Set(this._rawData, "billable_metric", value); } + } + + public required MetricGroup MetricGroup + { + get { return JsonModel.GetNotNullClass(this.RawData, "metric_group"); } + init { JsonModel.Set(this._rawData, "metric_group", value); } + } + + public required IReadOnlyList Usage + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "usage" + ); + } + init { JsonModel.Set(this._rawData, "usage", value); } + } + + public required ApiEnum ViewMode + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "view_mode" + ); + } + init { JsonModel.Set(this._rawData, "view_mode", value); } + } + + /// + public override void Validate() + { + this.BillableMetric.Validate(); + this.MetricGroup.Validate(); + foreach (var item in this.Usage) + { + item.Validate(); + } + this.ViewMode.Validate(); + } + + public GroupedSubscriptionUsageData() { } + + public GroupedSubscriptionUsageData(GroupedSubscriptionUsageData groupedSubscriptionUsageData) + : base(groupedSubscriptionUsageData) { } + + public GroupedSubscriptionUsageData(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedSubscriptionUsageData(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedSubscriptionUsageData FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedSubscriptionUsageDataFromRaw : IFromRawJson +{ + /// + public GroupedSubscriptionUsageData FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedSubscriptionUsageData.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedSubscriptionUsageDataBillableMetric, + GroupedSubscriptionUsageDataBillableMetricFromRaw + >) +)] +public sealed record class GroupedSubscriptionUsageDataBillableMetric : JsonModel +{ + public required string ID + { + get { return JsonModel.GetNotNullClass(this.RawData, "id"); } + init { JsonModel.Set(this._rawData, "id", value); } + } + + public required string Name + { + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } + } + + /// + public override void Validate() + { + _ = this.ID; + _ = this.Name; + } + + public GroupedSubscriptionUsageDataBillableMetric() { } + + public GroupedSubscriptionUsageDataBillableMetric( + GroupedSubscriptionUsageDataBillableMetric groupedSubscriptionUsageDataBillableMetric + ) + : base(groupedSubscriptionUsageDataBillableMetric) { } + + public GroupedSubscriptionUsageDataBillableMetric( + IReadOnlyDictionary rawData + ) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedSubscriptionUsageDataBillableMetric(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedSubscriptionUsageDataBillableMetric FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedSubscriptionUsageDataBillableMetricFromRaw + : IFromRawJson +{ + /// + public GroupedSubscriptionUsageDataBillableMetric FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedSubscriptionUsageDataBillableMetric.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class MetricGroup : JsonModel +{ + public required string PropertyKey + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_key"); } + init { JsonModel.Set(this._rawData, "property_key", value); } + } + + public required string PropertyValue + { + get { return JsonModel.GetNotNullClass(this.RawData, "property_value"); } + init { JsonModel.Set(this._rawData, "property_value", value); } + } + + /// + public override void Validate() + { + _ = this.PropertyKey; + _ = this.PropertyValue; + } + + public MetricGroup() { } + + public MetricGroup(MetricGroup metricGroup) + : base(metricGroup) { } + + public MetricGroup(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + MetricGroup(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static MetricGroup FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class MetricGroupFromRaw : IFromRawJson +{ + /// + public MetricGroup FromRawUnchecked(IReadOnlyDictionary rawData) => + MetricGroup.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + GroupedSubscriptionUsageDataUsage, + GroupedSubscriptionUsageDataUsageFromRaw + >) +)] +public sealed record class GroupedSubscriptionUsageDataUsage : JsonModel +{ + public required double Quantity + { + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } + } + + public required System::DateTimeOffset TimeframeEnd + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_end" + ); + } + init { JsonModel.Set(this._rawData, "timeframe_end", value); } + } + + public required System::DateTimeOffset TimeframeStart + { + get + { + return JsonModel.GetNotNullStruct( + this.RawData, + "timeframe_start" + ); + } + init { JsonModel.Set(this._rawData, "timeframe_start", value); } + } + + /// + public override void Validate() + { + _ = this.Quantity; + _ = this.TimeframeEnd; + _ = this.TimeframeStart; + } + + public GroupedSubscriptionUsageDataUsage() { } + + public GroupedSubscriptionUsageDataUsage( + GroupedSubscriptionUsageDataUsage groupedSubscriptionUsageDataUsage + ) + : base(groupedSubscriptionUsageDataUsage) { } + + public GroupedSubscriptionUsageDataUsage(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + GroupedSubscriptionUsageDataUsage(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static GroupedSubscriptionUsageDataUsage FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class GroupedSubscriptionUsageDataUsageFromRaw : IFromRawJson +{ + /// + public GroupedSubscriptionUsageDataUsage FromRawUnchecked( + IReadOnlyDictionary rawData + ) => GroupedSubscriptionUsageDataUsage.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(GroupedSubscriptionUsageDataViewModeConverter))] +public enum GroupedSubscriptionUsageDataViewMode +{ + Periodic, + Cumulative, +} + +sealed class GroupedSubscriptionUsageDataViewModeConverter + : JsonConverter +{ + public override GroupedSubscriptionUsageDataViewMode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "periodic" => GroupedSubscriptionUsageDataViewMode.Periodic, + "cumulative" => GroupedSubscriptionUsageDataViewMode.Cumulative, + _ => (GroupedSubscriptionUsageDataViewMode)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + GroupedSubscriptionUsageDataViewMode value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + GroupedSubscriptionUsageDataViewMode.Periodic => "periodic", + GroupedSubscriptionUsageDataViewMode.Cumulative => "cumulative", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } } diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsage.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsage.cs deleted file mode 100644 index 97e794b0..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsage.cs +++ /dev/null @@ -1,71 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using GroupedSubscriptionUsageProperties = Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class GroupedSubscriptionUsage - : Orb::ModelBase, - Orb::IFromRaw -{ - public required Generic::List Data - { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public Models::PaginationMetadata? PaginationMetadata - { - get - { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - foreach (var item in this.Data) - { - item.Validate(); - } - this.PaginationMetadata?.Validate(); - } - - public GroupedSubscriptionUsage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - GroupedSubscriptionUsage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static GroupedSubscriptionUsage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/Data.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/Data.cs deleted file mode 100644 index 4e8d1f06..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/Data.cs +++ /dev/null @@ -1,100 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required DataProperties::BillableMetric BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billable_metric"); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DataProperties::MetricGroup MetricGroup - { - get - { - if (!this.Properties.TryGetValue("metric_group", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "metric_group", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("metric_group"); - } - set { this.Properties["metric_group"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::List Usage - { - get - { - if (!this.Properties.TryGetValue("usage", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("usage", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("usage"); - } - set { this.Properties["usage"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DataProperties::ViewMode ViewMode - { - get - { - if (!this.Properties.TryGetValue("view_mode", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "view_mode", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("view_mode"); - } - set { this.Properties["view_mode"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BillableMetric.Validate(); - this.MetricGroup.Validate(); - foreach (var item in this.Usage) - { - item.Validate(); - } - this.ViewMode.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/BillableMetric.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/BillableMetric.cs deleted file mode 100644 index 732fd8ac..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/BillableMetric.cs +++ /dev/null @@ -1,61 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BillableMetric : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Name; - } - - public BillableMetric() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BillableMetric(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BillableMetric FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/MetricGroup.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/MetricGroup.cs deleted file mode 100644 index fa156b71..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/MetricGroup.cs +++ /dev/null @@ -1,67 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class MetricGroup : Orb::ModelBase, Orb::IFromRaw -{ - public required string PropertyKey - { - get - { - if (!this.Properties.TryGetValue("property_key", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "property_key", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("property_key"); - } - set { this.Properties["property_key"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string PropertyValue - { - get - { - if (!this.Properties.TryGetValue("property_value", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "property_value", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("property_value"); - } - set { this.Properties["property_value"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.PropertyKey; - _ = this.PropertyValue; - } - - public MetricGroup() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - MetricGroup(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static MetricGroup FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/Usage.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/Usage.cs deleted file mode 100644 index ac679378..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/Usage.cs +++ /dev/null @@ -1,79 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Usage : Orb::ModelBase, Orb::IFromRaw -{ - public required double Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeEnd - { - get - { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeStart - { - get - { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Quantity; - _ = this.TimeframeEnd; - _ = this.TimeframeStart; - } - - public Usage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Usage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Usage FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/ViewMode.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/ViewMode.cs deleted file mode 100644 index e4ad985c..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/GroupedSubscriptionUsageProperties/DataProperties/ViewMode.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.GroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ViewMode(string value) : Orb::IEnum -{ - public static readonly ViewMode Periodic = new("periodic"); - - public static readonly ViewMode Cumulative = new("cumulative"); - - readonly string _value = value; - - public enum Value - { - Periodic, - Cumulative, - } - - public Value Known() => - _value switch - { - "periodic" => Value.Periodic, - "cumulative" => Value.Cumulative, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ViewMode FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsage.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsage.cs deleted file mode 100644 index 326c4d6d..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsage.cs +++ /dev/null @@ -1,54 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using UngroupedSubscriptionUsageProperties = Orb.Models.Subscriptions.SubscriptionUsageProperties.UngroupedSubscriptionUsageProperties; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UngroupedSubscriptionUsage - : Orb::ModelBase, - Orb::IFromRaw -{ - public required Generic::List Data - { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>( - element - ) ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - foreach (var item in this.Data) - { - item.Validate(); - } - } - - public UngroupedSubscriptionUsage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UngroupedSubscriptionUsage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static UngroupedSubscriptionUsage FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/Data.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/Data.cs deleted file mode 100644 index c44b1249..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/Data.cs +++ /dev/null @@ -1,83 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using DataProperties = Orb.Models.Subscriptions.SubscriptionUsageProperties.UngroupedSubscriptionUsageProperties.DataProperties; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.UngroupedSubscriptionUsageProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Data : Orb::ModelBase, Orb::IFromRaw -{ - public required DataProperties::BillableMetric BillableMetric - { - get - { - if (!this.Properties.TryGetValue("billable_metric", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "billable_metric", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("billable_metric"); - } - set { this.Properties["billable_metric"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Generic::List Usage - { - get - { - if (!this.Properties.TryGetValue("usage", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("usage", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("usage"); - } - set { this.Properties["usage"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required DataProperties::ViewMode ViewMode - { - get - { - if (!this.Properties.TryGetValue("view_mode", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "view_mode", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("view_mode"); - } - set { this.Properties["view_mode"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.BillableMetric.Validate(); - foreach (var item in this.Usage) - { - item.Validate(); - } - this.ViewMode.Validate(); - } - - public Data() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Data(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Data FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/BillableMetric.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/BillableMetric.cs deleted file mode 100644 index 1cab95a5..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/BillableMetric.cs +++ /dev/null @@ -1,61 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.UngroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class BillableMetric : Orb::ModelBase, Orb::IFromRaw -{ - public required string ID - { - get - { - if (!this.Properties.TryGetValue("id", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("id", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("id"); - } - set { this.Properties["id"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string Name - { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.ID; - _ = this.Name; - } - - public BillableMetric() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - BillableMetric(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static BillableMetric FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/Usage.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/Usage.cs deleted file mode 100644 index a0678a5b..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/Usage.cs +++ /dev/null @@ -1,79 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.UngroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Usage : Orb::ModelBase, Orb::IFromRaw -{ - public required double Quantity - { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeEnd - { - get - { - if (!this.Properties.TryGetValue("timeframe_end", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_end", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_end"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required System::DateTime TimeframeStart - { - get - { - if (!this.Properties.TryGetValue("timeframe_start", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "timeframe_start", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["timeframe_start"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.Quantity; - _ = this.TimeframeEnd; - _ = this.TimeframeStart; - } - - public Usage() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Usage(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Usage FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/ViewMode.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/ViewMode.cs deleted file mode 100644 index 83f67c13..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageProperties/UngroupedSubscriptionUsageProperties/DataProperties/ViewMode.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions.SubscriptionUsageProperties.UngroupedSubscriptionUsageProperties.DataProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ViewMode(string value) : Orb::IEnum -{ - public static readonly ViewMode Periodic = new("periodic"); - - public static readonly ViewMode Cumulative = new("cumulative"); - - readonly string _value = value; - - public enum Value - { - Periodic, - Cumulative, - } - - public Value Known() => - _value switch - { - "periodic" => Value.Periodic, - "cumulative" => Value.Cumulative, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ViewMode FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/Subscriptions/SubscriptionUsageVariants/All.cs b/src/Orb/Models/Subscriptions/SubscriptionUsageVariants/All.cs deleted file mode 100644 index f8c6a607..00000000 --- a/src/Orb/Models/Subscriptions/SubscriptionUsageVariants/All.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using Subscriptions = Orb.Models.Subscriptions; -using SubscriptionUsageProperties = Orb.Models.Subscriptions.SubscriptionUsageProperties; - -namespace Orb.Models.Subscriptions.SubscriptionUsageVariants; - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - UngroupedSubscriptionUsage, - SubscriptionUsageProperties::UngroupedSubscriptionUsage - >) -)] -public sealed record class UngroupedSubscriptionUsage( - SubscriptionUsageProperties::UngroupedSubscriptionUsage Value -) - : Subscriptions::SubscriptionUsage, - Orb::IVariant< - UngroupedSubscriptionUsage, - SubscriptionUsageProperties::UngroupedSubscriptionUsage - > -{ - public static UngroupedSubscriptionUsage From( - SubscriptionUsageProperties::UngroupedSubscriptionUsage value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} - -[Serialization::JsonConverter( - typeof(Orb::VariantConverter< - GroupedSubscriptionUsage, - SubscriptionUsageProperties::GroupedSubscriptionUsage - >) -)] -public sealed record class GroupedSubscriptionUsage( - SubscriptionUsageProperties::GroupedSubscriptionUsage Value -) - : Subscriptions::SubscriptionUsage, - Orb::IVariant< - GroupedSubscriptionUsage, - SubscriptionUsageProperties::GroupedSubscriptionUsage - > -{ - public static GroupedSubscriptionUsage From( - SubscriptionUsageProperties::GroupedSubscriptionUsage value - ) - { - return new(value); - } - - public override void Validate() - { - this.Value.Validate(); - } -} diff --git a/src/Orb/Models/Subscriptions/Subscriptions.cs b/src/Orb/Models/Subscriptions/Subscriptions.cs deleted file mode 100644 index 8e4c87f0..00000000 --- a/src/Orb/Models/Subscriptions/Subscriptions.cs +++ /dev/null @@ -1,71 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.Subscriptions; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Subscriptions : Orb::ModelBase, Orb::IFromRaw -{ - public required Generic::List Data - { - get - { - if (!this.Properties.TryGetValue("data", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("data", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("data"); - } - set { this.Properties["data"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required Models::PaginationMetadata PaginationMetadata - { - get - { - if (!this.Properties.TryGetValue("pagination_metadata", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "pagination_metadata", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("pagination_metadata"); - } - set - { - this.Properties["pagination_metadata"] = Json::JsonSerializer.SerializeToElement(value); - } - } - - public override void Validate() - { - foreach (var item in this.Data) - { - item.Validate(); - } - this.PaginationMetadata.Validate(); - } - - public Subscriptions() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Subscriptions(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Subscriptions FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/TaxAmount.cs b/src/Orb/Models/TaxAmount.cs index b8b79337..f1a1ba48 100644 --- a/src/Orb/Models/TaxAmount.cs +++ b/src/Orb/Models/TaxAmount.cs @@ -1,32 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TaxAmount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TaxAmount : JsonModel { /// /// The amount of additional tax incurred by this tax rate. /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } /// @@ -34,23 +24,8 @@ public required string Amount /// public required string TaxRateDescription { - get - { - if (!this.Properties.TryGetValue("tax_rate_description", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_rate_description", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tax_rate_description"); - } - set - { - this.Properties["tax_rate_description"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNotNullClass(this.RawData, "tax_rate_description"); } + init { JsonModel.Set(this._rawData, "tax_rate_description", value); } } /// @@ -58,22 +33,11 @@ public required string TaxRateDescription /// public required string? TaxRatePercentage { - get - { - if (!this.Properties.TryGetValue("tax_rate_percentage", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tax_rate_percentage", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["tax_rate_percentage"] = Json::JsonSerializer.SerializeToElement(value); - } + get { return JsonModel.GetNullableClass(this.RawData, "tax_rate_percentage"); } + init { JsonModel.Set(this._rawData, "tax_rate_percentage", value); } } + /// public override void Validate() { _ = this.Amount; @@ -83,18 +47,32 @@ public override void Validate() public TaxAmount() { } + public TaxAmount(TaxAmount taxAmount) + : base(taxAmount) { } + + public TaxAmount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TaxAmount(Generic::Dictionary properties) + [SetsRequiredMembers] + TaxAmount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static TaxAmount FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static TaxAmount FromRawUnchecked(IReadOnlyDictionary rawData) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } + +class TaxAmountFromRaw : IFromRawJson +{ + /// + public TaxAmount FromRawUnchecked(IReadOnlyDictionary rawData) => + TaxAmount.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/Tier.cs b/src/Orb/Models/Tier.cs deleted file mode 100644 index 7ba90ece..00000000 --- a/src/Orb/Models/Tier.cs +++ /dev/null @@ -1,86 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class Tier : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Exclusive tier starting value - /// - public required double FirstUnit - { - get - { - if (!this.Properties.TryGetValue("first_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "first_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["first_unit"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Amount per unit - /// - public required string UnitAmount - { - get - { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); - } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Inclusive tier ending value. If null, this is treated as the last tier - /// - public double? LastUnit - { - get - { - if (!this.Properties.TryGetValue("last_unit", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["last_unit"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.FirstUnit; - _ = this.UnitAmount; - _ = this.LastUnit; - } - - public Tier() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - Tier(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static Tier FromRawUnchecked(Generic::Dictionary properties) - { - return new(properties); - } -} diff --git a/src/Orb/Models/TierConfig.cs b/src/Orb/Models/TierConfig.cs deleted file mode 100644 index 453a6eb0..00000000 --- a/src/Orb/Models/TierConfig.cs +++ /dev/null @@ -1,82 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TierConfig : Orb::ModelBase, Orb::IFromRaw -{ - public required double FirstUnit - { - get - { - if (!this.Properties.TryGetValue("first_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "first_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["first_unit"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required double? LastUnit - { - get - { - if (!this.Properties.TryGetValue("last_unit", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "last_unit", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["last_unit"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public required string UnitAmount - { - get - { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); - } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - _ = this.FirstUnit; - _ = this.LastUnit; - _ = this.UnitAmount; - } - - public TierConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TierConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TierConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/TierSubLineItem.cs b/src/Orb/Models/TierSubLineItem.cs index 79cc7494..8b6f1e94 100644 --- a/src/Orb/Models/TierSubLineItem.cs +++ b/src/Orb/Models/TierSubLineItem.cs @@ -1,107 +1,63 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using TierSubLineItemProperties = Orb.Models.TierSubLineItemProperties; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TierSubLineItem : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TierSubLineItem : JsonModel { /// /// The total amount for this sub line item. /// public required string Amount { - get - { - if (!this.Properties.TryGetValue("amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("amount"); - } - set { this.Properties["amount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "amount"); } + init { JsonModel.Set(this._rawData, "amount", value); } } public required SubLineItemGrouping? Grouping { - get - { - if (!this.Properties.TryGetValue("grouping", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "grouping", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["grouping"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "grouping"); } + init { JsonModel.Set(this._rawData, "grouping", value); } } public required string Name { - get - { - if (!this.Properties.TryGetValue("name", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("name", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("name"); - } - set { this.Properties["name"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "name"); } + init { JsonModel.Set(this._rawData, "name", value); } } public required double Quantity { - get - { - if (!this.Properties.TryGetValue("quantity", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "quantity", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["quantity"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "quantity"); } + init { JsonModel.Set(this._rawData, "quantity", value); } } public required TierConfig TierConfig { - get - { - if (!this.Properties.TryGetValue("tier_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tier_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tier_config"); - } - set { this.Properties["tier_config"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "tier_config"); } + init { JsonModel.Set(this._rawData, "tier_config", value); } } - public required TierSubLineItemProperties::Type Type + public required ApiEnum Type { get { - if (!this.Properties.TryGetValue("type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("type", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "type" + ); } - set { this.Properties["type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "type", value); } } + /// public override void Validate() { _ = this.Amount; @@ -114,18 +70,134 @@ public override void Validate() public TierSubLineItem() { } + public TierSubLineItem(TierSubLineItem tierSubLineItem) + : base(tierSubLineItem) { } + + public TierSubLineItem(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TierSubLineItem(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TierSubLineItem FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TierSubLineItemFromRaw : IFromRawJson +{ + /// + public TierSubLineItem FromRawUnchecked(IReadOnlyDictionary rawData) => + TierSubLineItem.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TierConfig : JsonModel +{ + public required double FirstUnit + { + get { return JsonModel.GetNotNullStruct(this.RawData, "first_unit"); } + init { JsonModel.Set(this._rawData, "first_unit", value); } + } + + public required double? LastUnit + { + get { return JsonModel.GetNullableStruct(this.RawData, "last_unit"); } + init { JsonModel.Set(this._rawData, "last_unit", value); } + } + + public required string UnitAmount + { + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + public override void Validate() + { + _ = this.FirstUnit; + _ = this.LastUnit; + _ = this.UnitAmount; + } + + public TierConfig() { } + + public TierConfig(TierConfig tierConfig) + : base(tierConfig) { } + + public TierConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TierSubLineItem(Generic::Dictionary properties) + [SetsRequiredMembers] + TierConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static TierSubLineItem FromRawUnchecked( - Generic::Dictionary properties + /// + public static TierConfig FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TierConfigFromRaw : IFromRawJson +{ + /// + public TierConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + TierConfig.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TierSubLineItemTypeConverter))] +public enum TierSubLineItemType +{ + Tier, +} + +sealed class TierSubLineItemTypeConverter : JsonConverter +{ + public override TierSubLineItemType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "tier" => TierSubLineItemType.Tier, + _ => (TierSubLineItemType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TierSubLineItemType value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + TierSubLineItemType.Tier => "tier", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/TierSubLineItemProperties/Type.cs b/src/Orb/Models/TierSubLineItemProperties/Type.cs deleted file mode 100644 index a3ca76b9..00000000 --- a/src/Orb/Models/TierSubLineItemProperties/Type.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.TierSubLineItemProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Type(string value) : Orb::IEnum -{ - public static readonly Type Tier = new("tier"); - - readonly string _value = value; - - public enum Value - { - Tier, - } - - public Value Known() => - _value switch - { - "tier" => Value.Tier, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Type FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/TieredBPSConfig.cs b/src/Orb/Models/TieredBPSConfig.cs deleted file mode 100644 index bf6b5d0a..00000000 --- a/src/Orb/Models/TieredBPSConfig.cs +++ /dev/null @@ -1,53 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredBPSConfig : Orb::ModelBase, Orb::IFromRaw -{ - /// - /// Tiers for a Graduated BPS pricing model, where usage is bucketed into specified tiers - /// - public required Generic::List Tiers - { - get - { - if (!this.Properties.TryGetValue("tiers", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("tiers", "Missing required argument"); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tiers"); - } - set { this.Properties["tiers"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - foreach (var item in this.Tiers) - { - item.Validate(); - } - } - - public TieredBPSConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredBPSConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredBPSConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/TieredConfig.cs b/src/Orb/Models/TieredConfig.cs index 933a75bf..e8aa719d 100644 --- a/src/Orb/Models/TieredConfig.cs +++ b/src/Orb/Models/TieredConfig.cs @@ -1,53 +1,89 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredConfig : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for tiered pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TieredConfig : JsonModel { /// /// Tiers for rating based on total usage quantities into the specified tier /// - public required Generic::List Tiers + public required IReadOnlyList Tiers { - get + get { return JsonModel.GetNotNullClass>(this.RawData, "tiers"); } + init { JsonModel.Set(this._rawData, "tiers", value); } + } + + /// + /// If true, subtotals from this price are prorated based on the service period + /// + public bool? Prorated + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorated"); } + init { - if (!this.Properties.TryGetValue("tiers", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("tiers", "Missing required argument"); + if (value == null) + { + return; + } - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("tiers"); + JsonModel.Set(this._rawData, "prorated", value); } - set { this.Properties["tiers"] = Json::JsonSerializer.SerializeToElement(value); } } + /// public override void Validate() { foreach (var item in this.Tiers) { item.Validate(); } + _ = this.Prorated; } public TieredConfig() { } + public TieredConfig(TieredConfig tieredConfig) + : base(tieredConfig) { } + + public TieredConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + TieredConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static TieredConfig FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static TieredConfig FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TieredConfig(List tiers) + : this() { - return new(properties); + this.Tiers = tiers; } } + +class TieredConfigFromRaw : IFromRawJson +{ + /// + public TieredConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + TieredConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/TieredConversionRateConfig.cs b/src/Orb/Models/TieredConversionRateConfig.cs deleted file mode 100644 index 8debcb1a..00000000 --- a/src/Orb/Models/TieredConversionRateConfig.cs +++ /dev/null @@ -1,76 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TieredConversionRateConfigProperties = Orb.Models.TieredConversionRateConfigProperties; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TieredConversionRateConfig - : Orb::ModelBase, - Orb::IFromRaw -{ - public required TieredConversionRateConfigProperties::ConversionRateType ConversionRateType - { - get - { - if (!this.Properties.TryGetValue("conversion_rate_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("conversion_rate_type"); - } - set - { - this.Properties["conversion_rate_type"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required ConversionRateTieredConfig TieredConfig - { - get - { - if (!this.Properties.TryGetValue("tiered_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "tiered_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("tiered_config"); - } - set { this.Properties["tiered_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.ConversionRateType.Validate(); - this.TieredConfig.Validate(); - } - - public TieredConversionRateConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TieredConversionRateConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TieredConversionRateConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/TieredConversionRateConfigProperties/ConversionRateType.cs b/src/Orb/Models/TieredConversionRateConfigProperties/ConversionRateType.cs deleted file mode 100644 index 47ad31a4..00000000 --- a/src/Orb/Models/TieredConversionRateConfigProperties/ConversionRateType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.TieredConversionRateConfigProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ConversionRateType(string value) : Orb::IEnum -{ - public static readonly ConversionRateType Tiered = new("tiered"); - - readonly string _value = value; - - public enum Value - { - Tiered, - } - - public Value Known() => - _value switch - { - "tiered" => Value.Tiered, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ConversionRateType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/TopLevel/TopLevelPingParams.cs b/src/Orb/Models/TopLevel/TopLevelPingParams.cs index 2e57eabe..f4261a89 100644 --- a/src/Orb/Models/TopLevel/TopLevelPingParams.cs +++ b/src/Orb/Models/TopLevel/TopLevelPingParams.cs @@ -1,33 +1,75 @@ -using Http = System.Net.Http; -using Orb = Orb; -using System = System; +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Net.Http; +using System.Text.Json; +using Orb.Core; namespace Orb.Models.TopLevel; /// /// This endpoint allows you to test your connection to the Orb API and check the /// validity of your API key, passed in the Authorization header. This is particularly -/// useful for checking that your environment is set up properly, and is a great choice -/// for connectors and integrations. +/// useful for checking that your environment is set up properly, and is a great +/// choice for connectors and integrations. /// -/// This API does not have any side-effects or return any Orb resources. +/// This API does not have any side-effects or return any Orb resources. /// -public sealed record class TopLevelPingParams : Orb::ParamsBase +public sealed record class TopLevelPingParams : ParamsBase { - public override System::Uri Url(Orb::IOrbClient client) + public TopLevelPingParams() { } + + public TopLevelPingParams(TopLevelPingParams topLevelPingParams) + : base(topLevelPingParams) { } + + public TopLevelPingParams( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TopLevelPingParams( + FrozenDictionary rawHeaderData, + FrozenDictionary rawQueryData + ) + { + this._rawHeaderData = [.. rawHeaderData]; + this._rawQueryData = [.. rawQueryData]; + } +#pragma warning restore CS8618 + + /// + public static TopLevelPingParams FromRawUnchecked( + IReadOnlyDictionary rawHeaderData, + IReadOnlyDictionary rawQueryData + ) + { + return new( + FrozenDictionary.ToFrozenDictionary(rawHeaderData), + FrozenDictionary.ToFrozenDictionary(rawQueryData) + ); + } + + public override Uri Url(ClientOptions options) { - return new System::UriBuilder(client.BaseUrl.ToString().TrimEnd('/') + "/ping") + return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/ping") { - Query = this.QueryString(client), + Query = this.QueryString(options), }.Uri; } - public void AddHeadersToRequest(Http::HttpRequestMessage request, Orb::IOrbClient client) + internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) { - Orb::ParamsBase.AddDefaultHeaders(request, client); - foreach (var item in this.HeaderProperties) + ParamsBase.AddDefaultHeaders(request, options); + foreach (var item in this.RawHeaderData) { - Orb::ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); + ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); } } } diff --git a/src/Orb/Models/TopLevel/TopLevelPingResponse.cs b/src/Orb/Models/TopLevel/TopLevelPingResponse.cs index 4d353ccb..f86c25ba 100644 --- a/src/Orb/Models/TopLevel/TopLevelPingResponse.cs +++ b/src/Orb/Models/TopLevel/TopLevelPingResponse.cs @@ -1,33 +1,22 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models.TopLevel; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TopLevelPingResponse - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TopLevelPingResponse : JsonModel { public required string Response { - get - { - if (!this.Properties.TryGetValue("response", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "response", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("response"); - } - set { this.Properties["response"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullClass(this.RawData, "response"); } + init { JsonModel.Set(this._rawData, "response", value); } } + /// public override void Validate() { _ = this.Response; @@ -35,18 +24,42 @@ public override void Validate() public TopLevelPingResponse() { } + public TopLevelPingResponse(TopLevelPingResponse topLevelPingResponse) + : base(topLevelPingResponse) { } + + public TopLevelPingResponse(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TopLevelPingResponse(Generic::Dictionary properties) + [SetsRequiredMembers] + TopLevelPingResponse(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static TopLevelPingResponse FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData ) { - return new(properties); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TopLevelPingResponse(string response) + : this() + { + this.Response = response; } } + +class TopLevelPingResponseFromRaw : IFromRawJson +{ + /// + public TopLevelPingResponse FromRawUnchecked( + IReadOnlyDictionary rawData + ) => TopLevelPingResponse.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/TransformPriceFilter.cs b/src/Orb/Models/TransformPriceFilter.cs deleted file mode 100644 index f72da26c..00000000 --- a/src/Orb/Models/TransformPriceFilter.cs +++ /dev/null @@ -1,97 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using TransformPriceFilterProperties = Orb.Models.TransformPriceFilterProperties; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TransformPriceFilter - : Orb::ModelBase, - Orb::IFromRaw -{ - /// - /// The property of the price to filter on. - /// - public required TransformPriceFilterProperties::Field Field - { - get - { - if (!this.Properties.TryGetValue("field", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException("field", "Missing required argument"); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("field"); - } - set { this.Properties["field"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// Should prices that match the filter be included or excluded. - /// - public required TransformPriceFilterProperties::Operator Operator - { - get - { - if (!this.Properties.TryGetValue("operator", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "operator", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("operator"); - } - set { this.Properties["operator"] = Json::JsonSerializer.SerializeToElement(value); } - } - - /// - /// The IDs or values that match this filter. - /// - public required Generic::List Values - { - get - { - if (!this.Properties.TryGetValue("values", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "values", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("values"); - } - set { this.Properties["values"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.Field.Validate(); - this.Operator.Validate(); - foreach (var item in this.Values) - { - _ = item; - } - } - - public TransformPriceFilter() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TransformPriceFilter(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static TransformPriceFilter FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/TransformPriceFilterProperties/Field.cs b/src/Orb/Models/TransformPriceFilterProperties/Field.cs deleted file mode 100644 index 8db10cad..00000000 --- a/src/Orb/Models/TransformPriceFilterProperties/Field.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.TransformPriceFilterProperties; - -/// -/// The property of the price to filter on. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Field(string value) : Orb::IEnum -{ - public static readonly Field PriceID = new("price_id"); - - public static readonly Field ItemID = new("item_id"); - - public static readonly Field PriceType = new("price_type"); - - public static readonly Field Currency = new("currency"); - - public static readonly Field PricingUnitID = new("pricing_unit_id"); - - readonly string _value = value; - - public enum Value - { - PriceID, - ItemID, - PriceType, - Currency, - PricingUnitID, - } - - public Value Known() => - _value switch - { - "price_id" => Value.PriceID, - "item_id" => Value.ItemID, - "price_type" => Value.PriceType, - "currency" => Value.Currency, - "pricing_unit_id" => Value.PricingUnitID, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Field FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/TransformPriceFilterProperties/Operator.cs b/src/Orb/Models/TransformPriceFilterProperties/Operator.cs deleted file mode 100644 index 6ad9c951..00000000 --- a/src/Orb/Models/TransformPriceFilterProperties/Operator.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.TransformPriceFilterProperties; - -/// -/// Should prices that match the filter be included or excluded. -/// -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class Operator(string value) : Orb::IEnum -{ - public static readonly Operator Includes = new("includes"); - - public static readonly Operator Excludes = new("excludes"); - - readonly string _value = value; - - public enum Value - { - Includes, - Excludes, - } - - public Value Known() => - _value switch - { - "includes" => Value.Includes, - "excludes" => Value.Excludes, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static Operator FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/TrialDiscount.cs b/src/Orb/Models/TrialDiscount.cs index a2a47684..b2d37545 100644 --- a/src/Orb/Models/TrialDiscount.cs +++ b/src/Orb/Models/TrialDiscount.cs @@ -1,78 +1,58 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using TrialDiscountProperties = Orb.Models.TrialDiscountProperties; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class TrialDiscount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TrialDiscount : JsonModel { - public required TrialDiscountProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// /// List of price_ids that this discount applies to. For plan/plan phase discounts, /// this can be a subset of prices. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this discount to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>(this.RawData, "filters"); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } public string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } /// @@ -80,21 +60,8 @@ public string? Reason /// public string? TrialAmountDiscount { - get - { - if ( - !this.Properties.TryGetValue("trial_amount_discount", out Json::JsonElement element) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["trial_amount_discount"] = Json::JsonSerializer.SerializeToElement( - value - ); - } + get { return JsonModel.GetNullableClass(this.RawData, "trial_amount_discount"); } + init { JsonModel.Set(this._rawData, "trial_amount_discount", value); } } /// @@ -104,31 +71,16 @@ public double? TrialPercentageDiscount { get { - if ( - !this.Properties.TryGetValue( - "trial_percentage_discount", - out Json::JsonElement element - ) - ) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set - { - this.Properties["trial_percentage_discount"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableStruct(this.RawData, "trial_percentage_discount"); } + init { JsonModel.Set(this._rawData, "trial_percentage_discount", value); } } + /// public override void Validate() { this.DiscountType.Validate(); - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters ?? []) { item.Validate(); @@ -140,18 +92,267 @@ public override void Validate() public TrialDiscount() { } + public TrialDiscount(TrialDiscount trialDiscount) + : base(trialDiscount) { } + + public TrialDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - TrialDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + TrialDiscount(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static TrialDiscount FromRawUnchecked( - Generic::Dictionary properties + /// + public static TrialDiscount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public TrialDiscount(ApiEnum discountType) + : this() + { + this.DiscountType = discountType; + } +} + +class TrialDiscountFromRaw : IFromRawJson +{ + /// + public TrialDiscount FromRawUnchecked(IReadOnlyDictionary rawData) => + TrialDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(TrialDiscountDiscountTypeConverter))] +public enum TrialDiscountDiscountType +{ + Trial, +} + +sealed class TrialDiscountDiscountTypeConverter : JsonConverter +{ + public override TrialDiscountDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "trial" => TrialDiscountDiscountType.Trial, + _ => (TrialDiscountDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TrialDiscountDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TrialDiscountDiscountType.Trial => "trial", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class TrialDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public TrialDiscountFilter() { } + + public TrialDiscountFilter(TrialDiscountFilter trialDiscountFilter) + : base(trialDiscountFilter) { } + + public TrialDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + TrialDiscountFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static TrialDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class TrialDiscountFilterFromRaw : IFromRawJson +{ + /// + public TrialDiscountFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + TrialDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(TrialDiscountFilterFieldConverter))] +public enum TrialDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class TrialDiscountFilterFieldConverter : JsonConverter +{ + public override TrialDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => TrialDiscountFilterField.PriceID, + "item_id" => TrialDiscountFilterField.ItemID, + "price_type" => TrialDiscountFilterField.PriceType, + "currency" => TrialDiscountFilterField.Currency, + "pricing_unit_id" => TrialDiscountFilterField.PricingUnitID, + _ => (TrialDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TrialDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + TrialDiscountFilterField.PriceID => "price_id", + TrialDiscountFilterField.ItemID => "item_id", + TrialDiscountFilterField.PriceType => "price_type", + TrialDiscountFilterField.Currency => "currency", + TrialDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(TrialDiscountFilterOperatorConverter))] +public enum TrialDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class TrialDiscountFilterOperatorConverter : JsonConverter +{ + public override TrialDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => TrialDiscountFilterOperator.Includes, + "excludes" => TrialDiscountFilterOperator.Excludes, + _ => (TrialDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + TrialDiscountFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + TrialDiscountFilterOperator.Includes => "includes", + TrialDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/TrialDiscountProperties/DiscountType.cs b/src/Orb/Models/TrialDiscountProperties/DiscountType.cs deleted file mode 100644 index 3b72a607..00000000 --- a/src/Orb/Models/TrialDiscountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.TrialDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Trial = new("trial"); - - readonly string _value = value; - - public enum Value - { - Trial, - } - - public Value Known() => - _value switch - { - "trial" => Value.Trial, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/UnitConfig.cs b/src/Orb/Models/UnitConfig.cs index e60a3050..71500e52 100644 --- a/src/Orb/Models/UnitConfig.cs +++ b/src/Orb/Models/UnitConfig.cs @@ -1,53 +1,86 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UnitConfig : Orb::ModelBase, Orb::IFromRaw +/// +/// Configuration for unit pricing +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UnitConfig : JsonModel { /// /// Rate per unit of usage /// public required string UnitAmount { - get + get { return JsonModel.GetNotNullClass(this.RawData, "unit_amount"); } + init { JsonModel.Set(this._rawData, "unit_amount", value); } + } + + /// + /// If true, subtotals from this price are prorated based on the service period + /// + public bool? Prorated + { + get { return JsonModel.GetNullableStruct(this.RawData, "prorated"); } + init { - if (!this.Properties.TryGetValue("unit_amount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_amount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_amount"); + if (value == null) + { + return; + } + + JsonModel.Set(this._rawData, "prorated", value); } - set { this.Properties["unit_amount"] = Json::JsonSerializer.SerializeToElement(value); } } + /// public override void Validate() { _ = this.UnitAmount; + _ = this.Prorated; } public UnitConfig() { } + public UnitConfig(UnitConfig unitConfig) + : base(unitConfig) { } + + public UnitConfig(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UnitConfig(Generic::Dictionary properties) + [SetsRequiredMembers] + UnitConfig(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static UnitConfig FromRawUnchecked( - Generic::Dictionary properties - ) + /// + public static UnitConfig FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public UnitConfig(string unitAmount) + : this() { - return new(properties); + this.UnitAmount = unitAmount; } } + +class UnitConfigFromRaw : IFromRawJson +{ + /// + public UnitConfig FromRawUnchecked(IReadOnlyDictionary rawData) => + UnitConfig.FromRawUnchecked(rawData); +} diff --git a/src/Orb/Models/UnitConversionRateConfig.cs b/src/Orb/Models/UnitConversionRateConfig.cs deleted file mode 100644 index 561755da..00000000 --- a/src/Orb/Models/UnitConversionRateConfig.cs +++ /dev/null @@ -1,76 +0,0 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; -using UnitConversionRateConfigProperties = Orb.Models.UnitConversionRateConfigProperties; - -namespace Orb.Models; - -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UnitConversionRateConfig - : Orb::ModelBase, - Orb::IFromRaw -{ - public required UnitConversionRateConfigProperties::ConversionRateType ConversionRateType - { - get - { - if (!this.Properties.TryGetValue("conversion_rate_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "conversion_rate_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("conversion_rate_type"); - } - set - { - this.Properties["conversion_rate_type"] = Json::JsonSerializer.SerializeToElement( - value - ); - } - } - - public required ConversionRateUnitConfig UnitConfig - { - get - { - if (!this.Properties.TryGetValue("unit_config", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "unit_config", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("unit_config"); - } - set { this.Properties["unit_config"] = Json::JsonSerializer.SerializeToElement(value); } - } - - public override void Validate() - { - this.ConversionRateType.Validate(); - this.UnitConfig.Validate(); - } - - public UnitConversionRateConfig() { } - -#pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UnitConversionRateConfig(Generic::Dictionary properties) - { - Properties = properties; - } -#pragma warning restore CS8618 - - public static UnitConversionRateConfig FromRawUnchecked( - Generic::Dictionary properties - ) - { - return new(properties); - } -} diff --git a/src/Orb/Models/UnitConversionRateConfigProperties/ConversionRateType.cs b/src/Orb/Models/UnitConversionRateConfigProperties/ConversionRateType.cs deleted file mode 100644 index 4b4115b8..00000000 --- a/src/Orb/Models/UnitConversionRateConfigProperties/ConversionRateType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.UnitConversionRateConfigProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class ConversionRateType(string value) : Orb::IEnum -{ - public static readonly ConversionRateType Unit = new("unit"); - - readonly string _value = value; - - public enum Value - { - Unit, - } - - public Value Known() => - _value switch - { - "unit" => Value.Unit, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static ConversionRateType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/UsageDiscount.cs b/src/Orb/Models/UsageDiscount.cs index f1e7278d..0814d44e 100644 --- a/src/Orb/Models/UsageDiscount.cs +++ b/src/Orb/Models/UsageDiscount.cs @@ -1,107 +1,76 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using UsageDiscountProperties = Orb.Models.UsageDiscountProperties; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UsageDiscount : Orb::ModelBase, Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UsageDiscount : JsonModel { - public required UsageDiscountProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element) - ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// /// Only available if discount_type is `usage`. Number of usage units that this /// discount is for /// - public required double UsageDiscount1 + public required double UsageDiscountValue { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } } /// /// List of price_ids that this discount applies to. For plan/plan phase discounts, /// this can be a subset of prices. /// - public Generic::List? AppliesToPriceIDs + public IReadOnlyList? AppliesToPriceIDs { get { - if (!this.Properties.TryGetValue("applies_to_price_ids", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); - } - set - { - this.Properties["applies_to_price_ids"] = Json::JsonSerializer.SerializeToElement( - value - ); + return JsonModel.GetNullableClass>(this.RawData, "applies_to_price_ids"); } + init { JsonModel.Set(this._rawData, "applies_to_price_ids", value); } } /// /// The filters that determine which prices to apply this discount to. /// - public Generic::List? Filters + public IReadOnlyList? Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize?>(element); + return JsonModel.GetNullableClass>(this.RawData, "filters"); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } public string? Reason { - get - { - if (!this.Properties.TryGetValue("reason", out Json::JsonElement element)) - return null; - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["reason"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNullableClass(this.RawData, "reason"); } + init { JsonModel.Set(this._rawData, "reason", value); } } + /// public override void Validate() { this.DiscountType.Validate(); - _ = this.UsageDiscount1; - foreach (var item in this.AppliesToPriceIDs ?? []) - { - _ = item; - } + _ = this.UsageDiscountValue; + _ = this.AppliesToPriceIDs; foreach (var item in this.Filters ?? []) { item.Validate(); @@ -111,18 +80,260 @@ public override void Validate() public UsageDiscount() { } + public UsageDiscount(UsageDiscount usageDiscount) + : base(usageDiscount) { } + + public UsageDiscount(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UsageDiscount(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UsageDiscount FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UsageDiscountFromRaw : IFromRawJson +{ + /// + public UsageDiscount FromRawUnchecked(IReadOnlyDictionary rawData) => + UsageDiscount.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(UsageDiscountDiscountTypeConverter))] +public enum UsageDiscountDiscountType +{ + Usage, +} + +sealed class UsageDiscountDiscountTypeConverter : JsonConverter +{ + public override UsageDiscountDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => UsageDiscountDiscountType.Usage, + _ => (UsageDiscountDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UsageDiscountDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UsageDiscountDiscountType.Usage => "usage", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UsageDiscountFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public UsageDiscountFilter() { } + + public UsageDiscountFilter(UsageDiscountFilter usageDiscountFilter) + : base(usageDiscountFilter) { } + + public UsageDiscountFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UsageDiscount(Generic::Dictionary properties) + [SetsRequiredMembers] + UsageDiscountFilter(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 - public static UsageDiscount FromRawUnchecked( - Generic::Dictionary properties + /// + public static UsageDiscountFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UsageDiscountFilterFromRaw : IFromRawJson +{ + /// + public UsageDiscountFilter FromRawUnchecked(IReadOnlyDictionary rawData) => + UsageDiscountFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(UsageDiscountFilterFieldConverter))] +public enum UsageDiscountFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class UsageDiscountFilterFieldConverter : JsonConverter +{ + public override UsageDiscountFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => UsageDiscountFilterField.PriceID, + "item_id" => UsageDiscountFilterField.ItemID, + "price_type" => UsageDiscountFilterField.PriceType, + "currency" => UsageDiscountFilterField.Currency, + "pricing_unit_id" => UsageDiscountFilterField.PricingUnitID, + _ => (UsageDiscountFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UsageDiscountFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UsageDiscountFilterField.PriceID => "price_id", + UsageDiscountFilterField.ItemID => "item_id", + UsageDiscountFilterField.PriceType => "price_type", + UsageDiscountFilterField.Currency => "currency", + UsageDiscountFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(UsageDiscountFilterOperatorConverter))] +public enum UsageDiscountFilterOperator +{ + Includes, + Excludes, +} + +sealed class UsageDiscountFilterOperatorConverter : JsonConverter +{ + public override UsageDiscountFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => UsageDiscountFilterOperator.Includes, + "excludes" => UsageDiscountFilterOperator.Excludes, + _ => (UsageDiscountFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UsageDiscountFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + UsageDiscountFilterOperator.Includes => "includes", + UsageDiscountFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/UsageDiscountInterval.cs b/src/Orb/Models/UsageDiscountInterval.cs index 967cf9e3..6fea6d22 100644 --- a/src/Orb/Models/UsageDiscountInterval.cs +++ b/src/Orb/Models/UsageDiscountInterval.cs @@ -1,116 +1,81 @@ -using CodeAnalysis = System.Diagnostics.CodeAnalysis; -using Generic = System.Collections.Generic; -using Json = System.Text.Json; -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using System.Text.Json.Serialization; +using Orb.Core; +using Orb.Exceptions; using System = System; -using UsageDiscountIntervalProperties = Orb.Models.UsageDiscountIntervalProperties; namespace Orb.Models; -[Serialization::JsonConverter(typeof(Orb::ModelConverter))] -public sealed record class UsageDiscountInterval - : Orb::ModelBase, - Orb::IFromRaw +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class UsageDiscountInterval : JsonModel { /// /// The price interval ids that this discount interval applies to. /// - public required Generic::List AppliesToPriceIntervalIDs + public required IReadOnlyList AppliesToPriceIntervalIDs { get { - if ( - !this.Properties.TryGetValue( - "applies_to_price_interval_ids", - out Json::JsonElement element - ) - ) - throw new System::ArgumentOutOfRangeException( - "applies_to_price_interval_ids", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("applies_to_price_interval_ids"); - } - set - { - this.Properties["applies_to_price_interval_ids"] = - Json::JsonSerializer.SerializeToElement(value); + return JsonModel.GetNotNullClass>( + this.RawData, + "applies_to_price_interval_ids" + ); } + init { JsonModel.Set(this._rawData, "applies_to_price_interval_ids", value); } } - public required UsageDiscountIntervalProperties::DiscountType DiscountType + public required ApiEnum DiscountType { get { - if (!this.Properties.TryGetValue("discount_type", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "discount_type", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize( - element - ) ?? throw new System::ArgumentNullException("discount_type"); + return JsonModel.GetNotNullClass>( + this.RawData, + "discount_type" + ); } - set { this.Properties["discount_type"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "discount_type", value); } } /// /// The end date of the discount interval. /// - public required System::DateTime? EndDate + public required System::DateTimeOffset? EndDate { get { - if (!this.Properties.TryGetValue("end_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "end_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNullableStruct(this.RawData, "end_date"); } - set { this.Properties["end_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "end_date", value); } } /// /// The filters that determine which prices this discount interval applies to. /// - public required Generic::List Filters + public required IReadOnlyList Filters { get { - if (!this.Properties.TryGetValue("filters", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "filters", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize>(element) - ?? throw new System::ArgumentNullException("filters"); + return JsonModel.GetNotNullClass>( + this.RawData, + "filters" + ); } - set { this.Properties["filters"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "filters", value); } } /// /// The start date of the discount interval. /// - public required System::DateTime StartDate + public required System::DateTimeOffset StartDate { get { - if (!this.Properties.TryGetValue("start_date", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "start_date", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); + return JsonModel.GetNotNullStruct(this.RawData, "start_date"); } - set { this.Properties["start_date"] = Json::JsonSerializer.SerializeToElement(value); } + init { JsonModel.Set(this._rawData, "start_date", value); } } /// @@ -119,25 +84,14 @@ public sealed record class UsageDiscountInterval /// public required double UsageDiscount { - get - { - if (!this.Properties.TryGetValue("usage_discount", out Json::JsonElement element)) - throw new System::ArgumentOutOfRangeException( - "usage_discount", - "Missing required argument" - ); - - return Json::JsonSerializer.Deserialize(element); - } - set { this.Properties["usage_discount"] = Json::JsonSerializer.SerializeToElement(value); } + get { return JsonModel.GetNotNullStruct(this.RawData, "usage_discount"); } + init { JsonModel.Set(this._rawData, "usage_discount", value); } } + /// public override void Validate() { - foreach (var item in this.AppliesToPriceIntervalIDs) - { - _ = item; - } + _ = this.AppliesToPriceIntervalIDs; this.DiscountType.Validate(); _ = this.EndDate; foreach (var item in this.Filters) @@ -150,18 +104,269 @@ public override void Validate() public UsageDiscountInterval() { } + public UsageDiscountInterval(UsageDiscountInterval usageDiscountInterval) + : base(usageDiscountInterval) { } + + public UsageDiscountInterval(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + #pragma warning disable CS8618 - [CodeAnalysis::SetsRequiredMembers] - UsageDiscountInterval(Generic::Dictionary properties) + [SetsRequiredMembers] + UsageDiscountInterval(FrozenDictionary rawData) { - Properties = properties; + this._rawData = [.. rawData]; } #pragma warning restore CS8618 + /// public static UsageDiscountInterval FromRawUnchecked( - Generic::Dictionary properties + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UsageDiscountIntervalFromRaw : IFromRawJson +{ + /// + public UsageDiscountInterval FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UsageDiscountInterval.FromRawUnchecked(rawData); +} + +[JsonConverter(typeof(UsageDiscountIntervalDiscountTypeConverter))] +public enum UsageDiscountIntervalDiscountType +{ + Usage, +} + +sealed class UsageDiscountIntervalDiscountTypeConverter + : JsonConverter +{ + public override UsageDiscountIntervalDiscountType Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "usage" => UsageDiscountIntervalDiscountType.Usage, + _ => (UsageDiscountIntervalDiscountType)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UsageDiscountIntervalDiscountType value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UsageDiscountIntervalDiscountType.Usage => "usage", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class UsageDiscountIntervalFilter : JsonModel +{ + /// + /// The property of the price to filter on. + /// + public required ApiEnum Field + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "field" + ); + } + init { JsonModel.Set(this._rawData, "field", value); } + } + + /// + /// Should prices that match the filter be included or excluded. + /// + public required ApiEnum Operator + { + get + { + return JsonModel.GetNotNullClass>( + this.RawData, + "operator" + ); + } + init { JsonModel.Set(this._rawData, "operator", value); } + } + + /// + /// The IDs or values that match this filter. + /// + public required IReadOnlyList Values + { + get { return JsonModel.GetNotNullClass>(this.RawData, "values"); } + init { JsonModel.Set(this._rawData, "values", value); } + } + + /// + public override void Validate() + { + this.Field.Validate(); + this.Operator.Validate(); + _ = this.Values; + } + + public UsageDiscountIntervalFilter() { } + + public UsageDiscountIntervalFilter(UsageDiscountIntervalFilter usageDiscountIntervalFilter) + : base(usageDiscountIntervalFilter) { } + + public UsageDiscountIntervalFilter(IReadOnlyDictionary rawData) + { + this._rawData = [.. rawData]; + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + UsageDiscountIntervalFilter(FrozenDictionary rawData) + { + this._rawData = [.. rawData]; + } +#pragma warning restore CS8618 + + /// + public static UsageDiscountIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class UsageDiscountIntervalFilterFromRaw : IFromRawJson +{ + /// + public UsageDiscountIntervalFilter FromRawUnchecked( + IReadOnlyDictionary rawData + ) => UsageDiscountIntervalFilter.FromRawUnchecked(rawData); +} + +/// +/// The property of the price to filter on. +/// +[JsonConverter(typeof(UsageDiscountIntervalFilterFieldConverter))] +public enum UsageDiscountIntervalFilterField +{ + PriceID, + ItemID, + PriceType, + Currency, + PricingUnitID, +} + +sealed class UsageDiscountIntervalFilterFieldConverter + : JsonConverter +{ + public override UsageDiscountIntervalFilterField Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "price_id" => UsageDiscountIntervalFilterField.PriceID, + "item_id" => UsageDiscountIntervalFilterField.ItemID, + "price_type" => UsageDiscountIntervalFilterField.PriceType, + "currency" => UsageDiscountIntervalFilterField.Currency, + "pricing_unit_id" => UsageDiscountIntervalFilterField.PricingUnitID, + _ => (UsageDiscountIntervalFilterField)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UsageDiscountIntervalFilterField value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + UsageDiscountIntervalFilterField.PriceID => "price_id", + UsageDiscountIntervalFilterField.ItemID => "item_id", + UsageDiscountIntervalFilterField.PriceType => "price_type", + UsageDiscountIntervalFilterField.Currency => "currency", + UsageDiscountIntervalFilterField.PricingUnitID => "pricing_unit_id", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Should prices that match the filter be included or excluded. +/// +[JsonConverter(typeof(UsageDiscountIntervalFilterOperatorConverter))] +public enum UsageDiscountIntervalFilterOperator +{ + Includes, + Excludes, +} + +sealed class UsageDiscountIntervalFilterOperatorConverter + : JsonConverter +{ + public override UsageDiscountIntervalFilterOperator Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "includes" => UsageDiscountIntervalFilterOperator.Includes, + "excludes" => UsageDiscountIntervalFilterOperator.Excludes, + _ => (UsageDiscountIntervalFilterOperator)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + UsageDiscountIntervalFilterOperator value, + JsonSerializerOptions options ) { - return new(properties); + JsonSerializer.Serialize( + writer, + value switch + { + UsageDiscountIntervalFilterOperator.Includes => "includes", + UsageDiscountIntervalFilterOperator.Excludes => "excludes", + _ => throw new OrbInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); } } diff --git a/src/Orb/Models/UsageDiscountIntervalProperties/DiscountType.cs b/src/Orb/Models/UsageDiscountIntervalProperties/DiscountType.cs deleted file mode 100644 index 89aa63db..00000000 --- a/src/Orb/Models/UsageDiscountIntervalProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.UsageDiscountIntervalProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Usage = new("usage"); - - readonly string _value = value; - - public enum Value - { - Usage, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Models/UsageDiscountProperties/DiscountType.cs b/src/Orb/Models/UsageDiscountProperties/DiscountType.cs deleted file mode 100644 index 1ea79aef..00000000 --- a/src/Orb/Models/UsageDiscountProperties/DiscountType.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Orb = Orb; -using Serialization = System.Text.Json.Serialization; -using System = System; - -namespace Orb.Models.UsageDiscountProperties; - -[Serialization::JsonConverter(typeof(Orb::EnumConverter))] -public sealed record class DiscountType(string value) : Orb::IEnum -{ - public static readonly DiscountType Usage = new("usage"); - - readonly string _value = value; - - public enum Value - { - Usage, - } - - public Value Known() => - _value switch - { - "usage" => Value.Usage, - _ => throw new System::ArgumentOutOfRangeException(nameof(_value)), - }; - - public string Raw() - { - return _value; - } - - public void Validate() - { - Known(); - } - - public static DiscountType FromRaw(string value) - { - return new(value); - } -} diff --git a/src/Orb/Null.cs b/src/Orb/Null.cs deleted file mode 100644 index 25a88350..00000000 --- a/src/Orb/Null.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Orb; - -public sealed record class Null -{ - Null() { } -} diff --git a/src/Orb/Orb.csproj b/src/Orb/Orb.csproj index 0bd11084..2c318a7e 100644 --- a/src/Orb/Orb.csproj +++ b/src/Orb/Orb.csproj @@ -1,32 +1,21 @@ - - The official .NET library for the Orb C# service API. - - SDK Code Generation Orb C# - Apache-2.0 - enable - 0.0.1 - net8.0 - latest - - true + + Orb C# + Orb + 0.1.0 + The official .NET library for the Orb API. + Library README.md - - true - true - - $(NoWarn),1570,1573,1574,1591 - - $(NoWarn),IL2026,IL3050 - Debug;Release - true - true - + + + + + + + + + + + \ No newline at end of file diff --git a/src/Orb/OrbClient.cs b/src/Orb/OrbClient.cs index 141236d4..c5466a46 100644 --- a/src/Orb/OrbClient.cs +++ b/src/Orb/OrbClient.cs @@ -1,165 +1,398 @@ -using Alerts = Orb.Service.Alerts; -using Beta = Orb.Service.Beta; -using Coupons = Orb.Service.Coupons; -using CreditNotes = Orb.Service.CreditNotes; -using Customers = Orb.Service.Customers; -using DimensionalPriceGroups = Orb.Service.DimensionalPriceGroups; -using Events = Orb.Service.Events; -using Http = System.Net.Http; -using InvoiceLineItems = Orb.Service.InvoiceLineItems; -using Invoices = Orb.Service.Invoices; -using Items = Orb.Service.Items; -using Metrics = Orb.Service.Metrics; -using Plans = Orb.Service.Plans; -using Prices = Orb.Service.Prices; -using SubscriptionChanges = Orb.Service.SubscriptionChanges; -using Subscriptions = Orb.Service.Subscriptions; -using System = System; -using TopLevel = Orb.Service.TopLevel; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Services; namespace Orb; +/// public sealed class OrbClient : IOrbClient { - public Http::HttpClient HttpClient { get; init; } = new Http::HttpClient(); +#if NET + static readonly Random Random = Random.Shared; +#else + static readonly ThreadLocal _threadLocalRandom = new(() => new Random()); - System::Lazy _baseUrl = new(() => - new System::Uri( - System::Environment.GetEnvironmentVariable("ORB_BASE_URL") - ?? "https://api.withorb.com/v1" - ) - ); - public System::Uri BaseUrl + static Random Random + { + get { return _threadLocalRandom.Value!; } + } +#endif + + readonly ClientOptions _options; + + /// + public HttpClient HttpClient + { + get { return this._options.HttpClient; } + init { this._options.HttpClient = value; } + } + + /// + public string BaseUrl + { + get { return this._options.BaseUrl; } + init { this._options.BaseUrl = value; } + } + + /// + public bool ResponseValidation + { + get { return this._options.ResponseValidation; } + init { this._options.ResponseValidation = value; } + } + + /// + public int? MaxRetries + { + get { return this._options.MaxRetries; } + init { this._options.MaxRetries = value; } + } + + /// + public TimeSpan? Timeout { - get { return _baseUrl.Value; } - init { _baseUrl = new(() => value); } + get { return this._options.Timeout; } + init { this._options.Timeout = value; } } - System::Lazy _apiKey = new(() => - System::Environment.GetEnvironmentVariable("ORB_API_KEY") - ?? throw new System::ArgumentNullException(nameof(APIKey)) - ); + /// public string APIKey { - get { return _apiKey.Value; } - init { _apiKey = new(() => value); } + get { return this._options.APIKey; } + init { this._options.APIKey = value; } + } + + /// + public string? WebhookSecret + { + get { return this._options.WebhookSecret; } + init { this._options.WebhookSecret = value; } } - readonly System::Lazy _topLevel; - public TopLevel::ITopLevelService TopLevel + /// + public IOrbClient WithOptions(Func modifier) + { + return new OrbClient(modifier(this._options)); + } + + readonly Lazy _topLevel; + public ITopLevelService TopLevel { get { return _topLevel.Value; } } - readonly System::Lazy _beta; - public Beta::IBetaService Beta + readonly Lazy _beta; + public IBetaService Beta { get { return _beta.Value; } } - readonly System::Lazy _coupons; - public Coupons::ICouponService Coupons + readonly Lazy _coupons; + public ICouponService Coupons { get { return _coupons.Value; } } - readonly System::Lazy _creditNotes; - public CreditNotes::ICreditNoteService CreditNotes + readonly Lazy _creditNotes; + public ICreditNoteService CreditNotes { get { return _creditNotes.Value; } } - readonly System::Lazy _customers; - public Customers::ICustomerService Customers + readonly Lazy _customers; + public ICustomerService Customers { get { return _customers.Value; } } - readonly System::Lazy _events; - public Events::IEventService Events + readonly Lazy _events; + public IEventService Events { get { return _events.Value; } } - readonly System::Lazy _invoiceLineItems; - public InvoiceLineItems::IInvoiceLineItemService InvoiceLineItems + readonly Lazy _invoiceLineItems; + public IInvoiceLineItemService InvoiceLineItems { get { return _invoiceLineItems.Value; } } - readonly System::Lazy _invoices; - public Invoices::IInvoiceService Invoices + readonly Lazy _invoices; + public IInvoiceService Invoices { get { return _invoices.Value; } } - readonly System::Lazy _items; - public Items::IItemService Items + readonly Lazy _items; + public IItemService Items { get { return _items.Value; } } - readonly System::Lazy _metrics; - public Metrics::IMetricService Metrics + readonly Lazy _metrics; + public IMetricService Metrics { get { return _metrics.Value; } } - readonly System::Lazy _plans; - public Plans::IPlanService Plans + readonly Lazy _plans; + public IPlanService Plans { get { return _plans.Value; } } - readonly System::Lazy _prices; - public Prices::IPriceService Prices + readonly Lazy _prices; + public IPriceService Prices { get { return _prices.Value; } } - readonly System::Lazy _subscriptions; - public Subscriptions::ISubscriptionService Subscriptions + readonly Lazy _subscriptions; + public ISubscriptionService Subscriptions { get { return _subscriptions.Value; } } - readonly System::Lazy _alerts; - public Alerts::IAlertService Alerts + readonly Lazy _alerts; + public IAlertService Alerts { get { return _alerts.Value; } } - readonly System::Lazy _dimensionalPriceGroups; - public DimensionalPriceGroups::IDimensionalPriceGroupService DimensionalPriceGroups + readonly Lazy _dimensionalPriceGroups; + public IDimensionalPriceGroupService DimensionalPriceGroups { get { return _dimensionalPriceGroups.Value; } } - readonly System::Lazy _subscriptionChanges; - public SubscriptionChanges::ISubscriptionChangeService SubscriptionChanges + readonly Lazy _subscriptionChanges; + public ISubscriptionChangeService SubscriptionChanges { get { return _subscriptionChanges.Value; } } - public OrbClient() + /// + public async Task Execute( + HttpRequest request, + CancellationToken cancellationToken = default + ) + where T : ParamsBase { - _topLevel = new(() => new TopLevel::TopLevelService(this)); - _beta = new(() => new Beta::BetaService(this)); - _coupons = new(() => new Coupons::CouponService(this)); - _creditNotes = new(() => new CreditNotes::CreditNoteService(this)); - _customers = new(() => new Customers::CustomerService(this)); - _events = new(() => new Events::EventService(this)); - _invoiceLineItems = new(() => new InvoiceLineItems::InvoiceLineItemService(this)); - _invoices = new(() => new Invoices::InvoiceService(this)); - _items = new(() => new Items::ItemService(this)); - _metrics = new(() => new Metrics::MetricService(this)); - _plans = new(() => new Plans::PlanService(this)); - _prices = new(() => new Prices::PriceService(this)); - _subscriptions = new(() => new Subscriptions::SubscriptionService(this)); - _alerts = new(() => new Alerts::AlertService(this)); - _dimensionalPriceGroups = new(() => - new DimensionalPriceGroups::DimensionalPriceGroupService(this) + var maxRetries = this.MaxRetries ?? ClientOptions.DefaultMaxRetries; + var retries = 0; + while (true) + { + HttpResponse? response = null; + try + { + response = await ExecuteOnce(request, retries, cancellationToken) + .ConfigureAwait(false); + } + catch (Exception e) + { + if (++retries > maxRetries || !ShouldRetry(e)) + { + throw; + } + } + + if (response != null && (++retries > maxRetries || !ShouldRetry(response))) + { + if (response.Message.IsSuccessStatusCode) + { + return response; + } + + try + { + throw OrbExceptionFactory.CreateApiException( + response.Message.StatusCode, + await response.ReadAsString(cancellationToken).ConfigureAwait(false) + ); + } + catch (HttpRequestException e) + { + throw new OrbIOException("I/O Exception", e); + } + finally + { + response.Dispose(); + } + } + + var backoff = ComputeRetryBackoff(retries, response); + response?.Dispose(); + await Task.Delay(backoff, cancellationToken).ConfigureAwait(false); + } + } + + async Task ExecuteOnce( + HttpRequest request, + int retryCount, + CancellationToken cancellationToken = default + ) + where T : ParamsBase + { + using HttpRequestMessage requestMessage = new( + request.Method, + request.Params.Url(this._options) + ) + { + Content = request.Params.BodyContent(), + }; + request.Params.AddHeadersToRequest(requestMessage, this._options); + if (!requestMessage.Headers.Contains("x-stainless-retry-count")) + { + requestMessage.Headers.Add("x-stainless-retry-count", retryCount.ToString()); + } + using CancellationTokenSource timeoutCts = new( + this.Timeout ?? ClientOptions.DefaultTimeout + ); + using var cts = CancellationTokenSource.CreateLinkedTokenSource( + timeoutCts.Token, + cancellationToken ); - _subscriptionChanges = new(() => new SubscriptionChanges::SubscriptionChangeService(this)); + HttpResponseMessage responseMessage; + try + { + responseMessage = await this + .HttpClient.SendAsync( + requestMessage, + HttpCompletionOption.ResponseHeadersRead, + cts.Token + ) + .ConfigureAwait(false); + } + catch (HttpRequestException e) + { + throw new OrbIOException("I/O exception", e); + } + return new() { Message = responseMessage, CancellationToken = cts.Token }; + } + + static TimeSpan ComputeRetryBackoff(int retries, HttpResponse? response) + { + TimeSpan? apiBackoff = ParseRetryAfterMsHeader(response) ?? ParseRetryAfterHeader(response); + if (apiBackoff != null && apiBackoff < TimeSpan.FromMinutes(1)) + { + // If the API asks us to wait a certain amount of time (and it's a reasonable amount), then just + // do what it says. + return (TimeSpan)apiBackoff; + } + + // Apply exponential backoff, but not more than the max. + var backoffSeconds = Math.Min(0.5 * Math.Pow(2.0, retries - 1), 8.0); + var jitter = 1.0 - 0.25 * Random.NextDouble(); + return TimeSpan.FromSeconds(backoffSeconds * jitter); + } + + static TimeSpan? ParseRetryAfterMsHeader(HttpResponse? response) + { + IEnumerable? headerValues = null; + response?.Message.Headers.TryGetValues("Retry-After-Ms", out headerValues); + var headerValue = headerValues == null ? null : Enumerable.FirstOrDefault(headerValues); + if (headerValue == null) + { + return null; + } + + if (float.TryParse(headerValue, out var retryAfterMs)) + { + return TimeSpan.FromMilliseconds(retryAfterMs); + } + + return null; + } + + static TimeSpan? ParseRetryAfterHeader(HttpResponse? response) + { + IEnumerable? headerValues = null; + response?.Message.Headers.TryGetValues("Retry-After", out headerValues); + var headerValue = headerValues == null ? null : Enumerable.FirstOrDefault(headerValues); + if (headerValue == null) + { + return null; + } + + if (float.TryParse(headerValue, out var retryAfterSeconds)) + { + return TimeSpan.FromSeconds(retryAfterSeconds); + } + else if (DateTimeOffset.TryParse(headerValue, out var retryAfterDate)) + { + return retryAfterDate - DateTimeOffset.Now; + } + + return null; + } + + static bool ShouldRetry(HttpResponse response) + { + if ( + response.Message.Headers.TryGetValues("X-Should-Retry", out var headerValues) + && bool.TryParse(Enumerable.FirstOrDefault(headerValues), out var shouldRetry) + ) + { + // If the server explicitly says whether to retry, then we obey. + return shouldRetry; + } + + return (int)response.Message.StatusCode switch + { + // Retry on request timeouts + 408 + or + // Retry on lock timeouts + 409 + or + // Retry on rate limits + 429 + or + // Retry internal errors + >= 500 => true, + _ => false, + }; + } + + static bool ShouldRetry(Exception e) + { + return e is IOException || e is OrbIOException; + } + + public void Dispose() => this.HttpClient.Dispose(); + + public OrbClient() + { + _options = new(); + + _topLevel = new(() => new TopLevelService(this)); + _beta = new(() => new BetaService(this)); + _coupons = new(() => new CouponService(this)); + _creditNotes = new(() => new CreditNoteService(this)); + _customers = new(() => new CustomerService(this)); + _events = new(() => new EventService(this)); + _invoiceLineItems = new(() => new InvoiceLineItemService(this)); + _invoices = new(() => new InvoiceService(this)); + _items = new(() => new ItemService(this)); + _metrics = new(() => new MetricService(this)); + _plans = new(() => new PlanService(this)); + _prices = new(() => new PriceService(this)); + _subscriptions = new(() => new SubscriptionService(this)); + _alerts = new(() => new AlertService(this)); + _dimensionalPriceGroups = new(() => new DimensionalPriceGroupService(this)); + _subscriptionChanges = new(() => new SubscriptionChangeService(this)); + } + + public OrbClient(ClientOptions options) + : this() + { + _options = options; } } diff --git a/src/Orb/ParamsBase.cs b/src/Orb/ParamsBase.cs deleted file mode 100644 index 60aee26f..00000000 --- a/src/Orb/ParamsBase.cs +++ /dev/null @@ -1,149 +0,0 @@ -using Generic = System.Collections.Generic; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Specialized = System.Collections.Specialized; -using System = System; -using Text = System.Text; -using Web = System.Web; - -namespace Orb; - -public abstract record class ParamsBase -{ - public Generic::Dictionary QueryProperties { get; set; } = []; - - public Generic::Dictionary HeaderProperties { get; set; } = []; - - public abstract System::Uri Url(IOrbClient client); - - protected static void AddQueryElementToCollection( - Specialized::NameValueCollection collection, - string key, - Json::JsonElement element - ) - { - switch (element.ValueKind) - { - case Json::JsonValueKind.Undefined: - case Json::JsonValueKind.Null: - collection.Add(key, ""); - break; - case Json::JsonValueKind.String: - case Json::JsonValueKind.Number: - collection.Add(key, element.ToString()); - break; - case Json::JsonValueKind.True: - collection.Add(key, "true"); - break; - case Json::JsonValueKind.False: - collection.Add(key, "false"); - break; - case Json::JsonValueKind.Object: - foreach (var item in element.EnumerateObject()) - { - AddQueryElementToCollection( - collection, - string.Format("{0}[{1}]", key, item.Name), - item.Value - ); - } - break; - case Json::JsonValueKind.Array: - foreach (var item in element.EnumerateArray()) - { - collection.Add( - string.Format("{0}[]", key), - item.ValueKind switch - { - Json::JsonValueKind.Null => "", - Json::JsonValueKind.True => "true", - Json::JsonValueKind.False => "false", - _ => item.GetString(), - } - ); - } - break; - } - } - - protected static void AddHeaderElementToRequest( - Http::HttpRequestMessage request, - string key, - Json::JsonElement element - ) - { - switch (element.ValueKind) - { - case Json::JsonValueKind.Undefined: - case Json::JsonValueKind.Null: - request.Headers.Add(key, ""); - break; - case Json::JsonValueKind.String: - case Json::JsonValueKind.Number: - request.Headers.Add(key, element.ToString()); - break; - case Json::JsonValueKind.True: - request.Headers.Add(key, "true"); - break; - case Json::JsonValueKind.False: - request.Headers.Add(key, "false"); - break; - case Json::JsonValueKind.Object: - foreach (var item in element.EnumerateObject()) - { - AddHeaderElementToRequest( - request, - string.Format("{0}.{1}", key, item.Name), - item.Value - ); - } - break; - case Json::JsonValueKind.Array: - foreach (var item in element.EnumerateArray()) - { - request.Headers.Add( - key, - item.ValueKind switch - { - Json::JsonValueKind.Null => "", - Json::JsonValueKind.True => "true", - Json::JsonValueKind.False => "false", - _ => item.GetString(), - } - ); - } - break; - } - } - - protected string QueryString(IOrbClient client) - { - Specialized::NameValueCollection collection = []; - foreach (var item in this.QueryProperties) - { - ParamsBase.AddQueryElementToCollection(collection, item.Key, item.Value); - } - Text::StringBuilder sb = new(); - bool first = true; - foreach (var key in collection.AllKeys) - { - foreach (var value in collection.GetValues(key) ?? []) - { - if (!first) - { - sb.Append('&'); - } - first = false; - sb.Append(Web::HttpUtility.UrlEncode(key)); - sb.Append('='); - sb.Append(Web::HttpUtility.UrlEncode(value)); - } - } - return sb.ToString(); - } - - protected static void AddDefaultHeaders(Http::HttpRequestMessage request, IOrbClient client) - { - request.Headers.Add("Authorization", string.Format("Bearer {0}", client.APIKey)); - } -} diff --git a/src/Orb/Service/Alerts/AlertService.cs b/src/Orb/Service/Alerts/AlertService.cs deleted file mode 100644 index 2326a4d1..00000000 --- a/src/Orb/Service/Alerts/AlertService.cs +++ /dev/null @@ -1,180 +0,0 @@ -using Alerts = Orb.Models.Alerts; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Alerts; - -public sealed class AlertService : IAlertService -{ - readonly Orb::IOrbClient _client; - - public AlertService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Retrieve(Alerts::AlertRetrieveParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Alerts::AlertUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List(Alerts::AlertListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task CreateForCustomer( - Alerts::AlertCreateForCustomerParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task CreateForExternalCustomer( - Alerts::AlertCreateForExternalCustomerParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task CreateForSubscription( - Alerts::AlertCreateForSubscriptionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Disable(Alerts::AlertDisableParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Enable(Alerts::AlertEnableParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Alerts/IAlertService.cs b/src/Orb/Service/Alerts/IAlertService.cs deleted file mode 100644 index fdc8c32f..00000000 --- a/src/Orb/Service/Alerts/IAlertService.cs +++ /dev/null @@ -1,85 +0,0 @@ -using Alerts = Orb.Models.Alerts; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Alerts; - -public interface IAlertService -{ - /// - /// This endpoint retrieves an alert by its ID. - /// - Tasks::Task Retrieve(Alerts::AlertRetrieveParams @params); - - /// - /// This endpoint updates the thresholds of an alert. - /// - Tasks::Task Update(Alerts::AlertUpdateParams @params); - - /// - /// This endpoint returns a list of alerts within Orb. - /// - /// The request must specify one of `customer_id`, `external_customer_id`, or `subscription_id`. - /// - /// If querying by subscripion_id, the endpoint will return the subscription level - /// alerts as well as the plan level alerts associated with the subscription. - /// - /// The list of alerts is ordered starting from the most recently created alert. - /// This endpoint follows Orb's [standardized pagination format](/api-reference/pagination). - /// - Tasks::Task List(Alerts::AlertListParams @params); - - /// - /// This endpoint creates a new alert to monitor a customer's credit balance. There - /// are three types of alerts that can be scoped to customers: `credit_balance_depleted`, - /// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have - /// a maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). - /// `credit_balance_dropped` alerts require a list of thresholds to be provided - /// while `credit_balance_depleted` and `credit_balance_recovered` alerts do not - /// require thresholds. - /// - Tasks::Task CreateForCustomer(Alerts::AlertCreateForCustomerParams @params); - - /// - /// This endpoint creates a new alert to monitor a customer's credit balance. There - /// are three types of alerts that can be scoped to customers: `credit_balance_depleted`, - /// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have - /// a maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). - /// `credit_balance_dropped` alerts require a list of thresholds to be provided - /// while `credit_balance_depleted` and `credit_balance_recovered` alerts do not - /// require thresholds. - /// - Tasks::Task CreateForExternalCustomer( - Alerts::AlertCreateForExternalCustomerParams @params - ); - - /// - /// This endpoint is used to create alerts at the subscription level. - /// - /// Subscription level alerts can be one of two types: `usage_exceeded` or `cost_exceeded`. - /// A `usage_exceeded` alert is scoped to a particular metric and is triggered when - /// the usage of that metric exceeds predefined thresholds during the current billing - /// cycle. A `cost_exceeded` alert is triggered when the total amount due during - /// the current billing cycle surpasses predefined thresholds. `cost_exceeded` - /// alerts do not include burndown of pre-purchase credits. Each subscription can - /// have one `cost_exceeded` alert and one `usage_exceeded` alert per metric that - /// is a part of the subscription. Alerts are triggered based on usage or cost - /// conditions met during the current billing cycle. - /// - Tasks::Task CreateForSubscription( - Alerts::AlertCreateForSubscriptionParams @params - ); - - /// - /// This endpoint allows you to disable an alert. To disable a plan-level alert - /// for a specific subscription, you must include the `subscription_id`. The `subscription_id` - /// is not required for customer or subscription level alerts. - /// - Tasks::Task Disable(Alerts::AlertDisableParams @params); - - /// - /// This endpoint allows you to enable an alert. To enable a plan-level alert for - /// a specific subscription, you must include the `subscription_id`. The `subscription_id` - /// is not required for customer or subscription level alerts. - /// - Tasks::Task Enable(Alerts::AlertEnableParams @params); -} diff --git a/src/Orb/Service/Beta/BetaService.cs b/src/Orb/Service/Beta/BetaService.cs deleted file mode 100644 index ad2dbaf3..00000000 --- a/src/Orb/Service/Beta/BetaService.cs +++ /dev/null @@ -1,93 +0,0 @@ -using Beta = Orb.Models.Beta; -using ExternalPlanID = Orb.Service.Beta.ExternalPlanID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using Plans = Orb.Models.Plans; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Beta; - -public sealed class BetaService : IBetaService -{ - readonly Orb::IOrbClient _client; - - public BetaService(Orb::IOrbClient client) - { - _client = client; - _externalPlanID = new(() => new ExternalPlanID::ExternalPlanIDService(client)); - } - - readonly System::Lazy _externalPlanID; - public ExternalPlanID::IExternalPlanIDService ExternalPlanID - { - get { return _externalPlanID.Value; } - } - - public async Tasks::Task CreatePlanVersion( - Beta::BetaCreatePlanVersionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchPlanVersion( - Beta::BetaFetchPlanVersionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task SetDefaultPlanVersion( - Beta::BetaSetDefaultPlanVersionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Beta/ExternalPlanID/ExternalPlanIDService.cs b/src/Orb/Service/Beta/ExternalPlanID/ExternalPlanIDService.cs deleted file mode 100644 index 0f1d9363..00000000 --- a/src/Orb/Service/Beta/ExternalPlanID/ExternalPlanIDService.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Beta = Orb.Models.Beta; -using ExternalPlanID = Orb.Models.Beta.ExternalPlanID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using Plans = Orb.Models.Plans; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Beta.ExternalPlanID; - -public sealed class ExternalPlanIDService : IExternalPlanIDService -{ - readonly Orb::IOrbClient _client; - - public ExternalPlanIDService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task CreatePlanVersion( - ExternalPlanID::ExternalPlanIDCreatePlanVersionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchPlanVersion( - ExternalPlanID::ExternalPlanIDFetchPlanVersionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task SetDefaultPlanVersion( - ExternalPlanID::ExternalPlanIDSetDefaultPlanVersionParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Beta/ExternalPlanID/IExternalPlanIDService.cs b/src/Orb/Service/Beta/ExternalPlanID/IExternalPlanIDService.cs deleted file mode 100644 index e271d366..00000000 --- a/src/Orb/Service/Beta/ExternalPlanID/IExternalPlanIDService.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Beta = Orb.Models.Beta; -using ExternalPlanID = Orb.Models.Beta.ExternalPlanID; -using Plans = Orb.Models.Plans; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Beta.ExternalPlanID; - -public interface IExternalPlanIDService -{ - /// - /// This API endpoint is in beta and its interface may change. It is recommended - /// for use only in test mode. - /// - /// This endpoint allows the creation of a new plan version for an existing plan. - /// - Tasks::Task CreatePlanVersion( - ExternalPlanID::ExternalPlanIDCreatePlanVersionParams @params - ); - - /// - /// This API endpoint is in beta and its interface may change. It is recommended - /// for use only in test mode. - /// - /// This endpoint is used to fetch a plan version. It returns the phases, prices, - /// and adjustments present on this version of the plan. - /// - Tasks::Task FetchPlanVersion( - ExternalPlanID::ExternalPlanIDFetchPlanVersionParams @params - ); - - /// - /// This API endpoint is in beta and its interface may change. It is recommended - /// for use only in test mode. - /// - /// This endpoint allows setting the default version of a plan. - /// - Tasks::Task SetDefaultPlanVersion( - ExternalPlanID::ExternalPlanIDSetDefaultPlanVersionParams @params - ); -} diff --git a/src/Orb/Service/Beta/IBetaService.cs b/src/Orb/Service/Beta/IBetaService.cs deleted file mode 100644 index 4a423a31..00000000 --- a/src/Orb/Service/Beta/IBetaService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Beta = Orb.Models.Beta; -using ExternalPlanID = Orb.Service.Beta.ExternalPlanID; -using Plans = Orb.Models.Plans; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Beta; - -public interface IBetaService -{ - ExternalPlanID::IExternalPlanIDService ExternalPlanID { get; } - - /// - /// This API endpoint is in beta and its interface may change. It is recommended - /// for use only in test mode. - /// - /// This endpoint allows the creation of a new plan version for an existing plan. - /// - Tasks::Task CreatePlanVersion(Beta::BetaCreatePlanVersionParams @params); - - /// - /// This API endpoint is in beta and its interface may change. It is recommended - /// for use only in test mode. - /// - /// This endpoint is used to fetch a plan version. It returns the phases, prices, - /// and adjustments present on this version of the plan. - /// - Tasks::Task FetchPlanVersion(Beta::BetaFetchPlanVersionParams @params); - - /// - /// This API endpoint is in beta and its interface may change. It is recommended - /// for use only in test mode. - /// - /// This endpoint allows setting the default version of a plan. - /// - Tasks::Task SetDefaultPlanVersion(Beta::BetaSetDefaultPlanVersionParams @params); -} diff --git a/src/Orb/Service/Coupons/CouponService.cs b/src/Orb/Service/Coupons/CouponService.cs deleted file mode 100644 index 1c0e7aad..00000000 --- a/src/Orb/Service/Coupons/CouponService.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Coupons = Orb.Models.Coupons; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using Subscriptions = Orb.Service.Coupons.Subscriptions; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Coupons; - -public sealed class CouponService : ICouponService -{ - readonly Orb::IOrbClient _client; - - public CouponService(Orb::IOrbClient client) - { - _client = client; - _subscriptions = new(() => new Subscriptions::SubscriptionService(client)); - } - - readonly System::Lazy _subscriptions; - public Subscriptions::ISubscriptionService Subscriptions - { - get { return _subscriptions.Value; } - } - - public async Tasks::Task Create(Coupons::CouponCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - Coupons::CouponListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Archive(Coupons::CouponArchiveParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(Coupons::CouponFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Coupons/ICouponService.cs b/src/Orb/Service/Coupons/ICouponService.cs deleted file mode 100644 index 441e168b..00000000 --- a/src/Orb/Service/Coupons/ICouponService.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Coupons = Orb.Models.Coupons; -using Subscriptions = Orb.Service.Coupons.Subscriptions; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Coupons; - -public interface ICouponService -{ - Subscriptions::ISubscriptionService Subscriptions { get; } - - /// - /// This endpoint allows the creation of coupons, which can then be redeemed at - /// subscription creation or plan change. - /// - Tasks::Task Create(Coupons::CouponCreateParams @params); - - /// - /// This endpoint returns a list of all coupons for an account in a list format. - /// - /// The list of coupons is ordered starting from the most recently created coupon. - /// The response also includes `pagination_metadata`, which lets the caller retrieve - /// the next page of results if they exist. More information about pagination can - /// be found in the Pagination-metadata schema. - /// - Tasks::Task List(Coupons::CouponListParams @params); - - /// - /// This endpoint allows a coupon to be archived. Archived coupons can no longer - /// be redeemed, and will be hidden from lists of active coupons. Additionally, - /// once a coupon is archived, its redemption code can be reused for a different coupon. - /// - Tasks::Task Archive(Coupons::CouponArchiveParams @params); - - /// - /// This endpoint retrieves a coupon by its ID. To fetch coupons by their redemption - /// code, use the [List coupons](list-coupons) endpoint with the redemption_code parameter. - /// - Tasks::Task Fetch(Coupons::CouponFetchParams @params); -} diff --git a/src/Orb/Service/Coupons/Subscriptions/ISubscriptionService.cs b/src/Orb/Service/Coupons/Subscriptions/ISubscriptionService.cs deleted file mode 100644 index c7369e98..00000000 --- a/src/Orb/Service/Coupons/Subscriptions/ISubscriptionService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Subscriptions = Orb.Models.Subscriptions; -using Subscriptions1 = Orb.Models.Coupons.Subscriptions; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Coupons.Subscriptions; - -public interface ISubscriptionService -{ - /// - /// This endpoint returns a list of all subscriptions that have redeemed a given - /// coupon as a [paginated](/api-reference/pagination) list, ordered starting from - /// the most recently created subscription. For a full discussion of the subscription - /// resource, see [Subscription](/core-concepts#subscription). - /// - Tasks::Task List(Subscriptions1::SubscriptionListParams @params); -} diff --git a/src/Orb/Service/Coupons/Subscriptions/SubscriptionService.cs b/src/Orb/Service/Coupons/Subscriptions/SubscriptionService.cs deleted file mode 100644 index b74143b7..00000000 --- a/src/Orb/Service/Coupons/Subscriptions/SubscriptionService.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using Subscriptions = Orb.Models.Subscriptions; -using Subscriptions1 = Orb.Models.Coupons.Subscriptions; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Coupons.Subscriptions; - -public sealed class SubscriptionService : ISubscriptionService -{ - readonly Orb::IOrbClient _client; - - public SubscriptionService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task List( - Subscriptions1::SubscriptionListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/CreditNotes/CreditNoteService.cs b/src/Orb/Service/CreditNotes/CreditNoteService.cs deleted file mode 100644 index 9fa4cefc..00000000 --- a/src/Orb/Service/CreditNotes/CreditNoteService.cs +++ /dev/null @@ -1,78 +0,0 @@ -using CreditNotes = Orb.Models.CreditNotes; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.CreditNotes; - -public sealed class CreditNoteService : ICreditNoteService -{ - readonly Orb::IOrbClient _client; - - public CreditNoteService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create(CreditNotes::CreditNoteCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - CreditNotes::CreditNoteListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(CreditNotes::CreditNoteFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/CreditNotes/ICreditNoteService.cs b/src/Orb/Service/CreditNotes/ICreditNoteService.cs deleted file mode 100644 index 5c6b74e1..00000000 --- a/src/Orb/Service/CreditNotes/ICreditNoteService.cs +++ /dev/null @@ -1,52 +0,0 @@ -using CreditNotes = Orb.Models.CreditNotes; -using Models = Orb.Models; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.CreditNotes; - -public interface ICreditNoteService -{ - /// - /// This endpoint is used to create a single [`Credit Note`](/invoicing/credit-notes). - /// - /// The credit note service period configuration supports two explicit modes: - /// - /// 1. Global service periods: Specify start_date and end_date at the credit note - /// level. These dates will be applied to all line items uniformly. - /// - /// 2. Individual service periods: Specify start_date and end_date for each line - /// item. When using this mode, ALL line items must have individual periods specified. - /// - /// 3. Default behavior: If no service periods are specified (neither global nor - /// individual), the original invoice line item service periods will be used. - /// - /// Note: Mixing global and individual service periods in the same request is not - /// allowed to prevent confusion. - /// - /// Service period dates are normalized to the start of the day in the customer's - /// timezone to ensure consistent handling across different timezones. - /// - /// Date Format: Use start_date and end_date with format "YYYY-MM-DD" (e.g., "2023-09-22") - /// to match other Orb APIs like /v1/invoice_line_items. - /// - /// Note: Both start_date and end_date are inclusive - the service period will cover - /// both the start date and end date completely (from start of start_date to end - /// of end_date). - /// - Tasks::Task Create(CreditNotes::CreditNoteCreateParams @params); - - /// - /// Get a paginated list of CreditNotes. Users can also filter by customer_id, subscription_id, - /// or external_customer_id. The credit notes will be returned in reverse chronological - /// order by `creation_time`. - /// - Tasks::Task List( - CreditNotes::CreditNoteListParams @params - ); - - /// - /// This endpoint is used to fetch a single [`Credit Note`](/invoicing/credit-notes) - /// given an identifier. - /// - Tasks::Task Fetch(CreditNotes::CreditNoteFetchParams @params); -} diff --git a/src/Orb/Service/Customers/BalanceTransactions/BalanceTransactionService.cs b/src/Orb/Service/Customers/BalanceTransactions/BalanceTransactionService.cs deleted file mode 100644 index fe0d770a..00000000 --- a/src/Orb/Service/Customers/BalanceTransactions/BalanceTransactionService.cs +++ /dev/null @@ -1,61 +0,0 @@ -using BalanceTransactions = Orb.Models.Customers.BalanceTransactions; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers.BalanceTransactions; - -public sealed class BalanceTransactionService : IBalanceTransactionService -{ - readonly Orb::IOrbClient _client; - - public BalanceTransactionService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create( - BalanceTransactions::BalanceTransactionCreateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - BalanceTransactions::BalanceTransactionListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Customers/BalanceTransactions/IBalanceTransactionService.cs b/src/Orb/Service/Customers/BalanceTransactions/IBalanceTransactionService.cs deleted file mode 100644 index 8a34f7e5..00000000 --- a/src/Orb/Service/Customers/BalanceTransactions/IBalanceTransactionService.cs +++ /dev/null @@ -1,42 +0,0 @@ -using BalanceTransactions = Orb.Models.Customers.BalanceTransactions; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers.BalanceTransactions; - -public interface IBalanceTransactionService -{ - /// - /// Creates an immutable balance transaction that updates the customer's balance - /// and returns back the newly created transaction. - /// - Tasks::Task Create( - BalanceTransactions::BalanceTransactionCreateParams @params - ); - - /// - /// ## The customer balance - /// - /// The customer balance is an amount in the customer's currency, which Orb automatically - /// applies to subsequent invoices. This balance can be adjusted manually via Orb's - /// webapp on the customer details page. You can use this balance to provide a - /// fixed mid-period credit to the customer. Commonly, this is done due to system - /// downtime/SLA violation, or an adhoc adjustment discussed with the customer. - /// - /// If the balance is a positive value at the time of invoicing, it represents that - /// the customer has credit that should be used to offset the amount due on the - /// next issued invoice. In this case, Orb will automatically reduce the next invoice - /// by the balance amount, and roll over any remaining balance if the invoice is - /// fully discounted. - /// - /// If the balance is a negative value at the time of invoicing, Orb will increase - /// the invoice's amount due with a positive adjustment, and reset the balance - /// to 0. - /// - /// This endpoint retrieves all customer balance transactions in reverse chronological - /// order for a single customer, providing a complete audit trail of all adjustments - /// and invoice applications. - /// - Tasks::Task List( - BalanceTransactions::BalanceTransactionListParams @params - ); -} diff --git a/src/Orb/Service/Customers/Costs/CostService.cs b/src/Orb/Service/Customers/Costs/CostService.cs deleted file mode 100644 index 743d300a..00000000 --- a/src/Orb/Service/Customers/Costs/CostService.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Costs = Orb.Models.Customers.Costs; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers.Costs; - -public sealed class CostService : ICostService -{ - readonly Orb::IOrbClient _client; - - public CostService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task List(Costs::CostListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task ListByExternalID( - Costs::CostListByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Customers/Costs/ICostService.cs b/src/Orb/Service/Customers/Costs/ICostService.cs deleted file mode 100644 index 66567259..00000000 --- a/src/Orb/Service/Customers/Costs/ICostService.cs +++ /dev/null @@ -1,209 +0,0 @@ -using Costs = Orb.Models.Customers.Costs; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers.Costs; - -public interface ICostService -{ - /// - /// This endpoint is used to fetch a day-by-day snapshot of a customer's costs - /// in Orb, calculated by applying pricing information to the underlying usage (see - /// the [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) - /// to fetch usage per metric, in usage units rather than a currency). - /// - /// This endpoint can be leveraged for internal tooling and to provide a more transparent - /// billing experience for your end users: - /// - /// 1. Understand the cost breakdown per line item historically and in real-time - /// for the current billing period. 2. Provide customer visibility into how different - /// services are contributing to the overall invoice with a per-day timeseries - /// (as compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) - /// resource, which represents a snapshot for the current period). 3. Assess how - /// minimums and discounts affect your customers by teasing apart costs directly - /// as a result of usage, as opposed to minimums and discounts at the plan and - /// price level. 4. Gain insight into key customer health metrics, such as the percent - /// utilization of the minimum committed spend. - /// - /// ## Fetching subscriptions By default, this endpoint fetches the currently active - /// subscription for the customer, and returns cost information for the subscription's - /// current billing period, broken down by each participating price. If there are - /// no currently active subscriptions, this will instead default to the most recently - /// active subscription or return an empty series if none are found. For example, - /// if your plan charges for compute hours, job runs, and data syncs, then this - /// endpoint would provide a daily breakdown of your customer's cost for each of - /// those axes. - /// - /// If timeframe bounds are specified, Orb fetches all subscriptions that were - /// active in that timeframe. If two subscriptions overlap on a single day, costs - /// from each price will be summed, and prices for both subscriptions will be included - /// in the breakdown. - /// - /// ## Prepaid plans For plans that include prices which deduct credits rather than - /// accrue in-arrears charges in a billable currency, this endpoint will return - /// the total deduction amount, in credits, for the specified timeframe. - /// - /// ## Cumulative subtotals and totals Since the subtotal and total must factor - /// in any billing-period level discounts and minimums, it's most meaningful to - /// consider costs relative to the start of the subscription's billing period. As - /// a result, by default this endpoint returns cumulative totals since the beginning - /// of the billing period. In particular, the `timeframe_start` of a returned timeframe - /// window is *always* the beginning of the billing period and `timeframe_end` is - /// incremented one day at a time to build the result. - /// - /// A customer that uses a few API calls a day but has a minimum commitment might - /// exhibit the following pattern for their subtotal and total in the first few - /// days of the month. Here, we assume that each API call is \$2.50, the customer's - /// plan has a monthly minimum of \$50 for this price, and that the subscription's - /// billing period bounds are aligned to the first of the month: - /// - /// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. - /// commitment) | | -----------| ----------- | ----------- | ----------- |----------- - /// | | 2023-02-01 | 2023-02-02 | 9 | \$22.50 | \$50.00 | | 2023-02-01 | 2023-02-03 - /// | 19 | \$47.50 | \$50.00 | | 2023-02-01 | 2023-02-04 | 20 | \$50.00 | \$50.00 - /// | | 2023-02-01 | 2023-02-05 | 28 | \$70.00 | \$70.00 | | 2023-02-01 | 2023-02-06 - /// | 36 | \$90.00 | \$90.00 | - /// - /// ### Periodic values When the query parameter `view_mode=periodic` is specified, - /// Orb will return an incremental day-by-day view of costs. In this case, there - /// will always be a one-day difference between `timeframe_start` and `timeframe_end` - /// for the timeframes returned. This is a transform on top of the cumulative costs, - /// calculated by taking the difference of each timeframe with the last. Note that - /// in the above example, the `Total` value would be 0 for the second two data - /// points, since the minimum commitment has not yet been hit and each day is not - /// contributing anything to the total cost. - /// - /// ## Timeframe bounds For an active subscription, both timeframes should be specified - /// in the request. If a subscription starts or ends within the timeframe, the - /// response will only include windows where the subscription is active. If a subscription - /// has ended, no timeframe bounds need to be specified and the response will default - /// to the billing period when the subscription was last active. - /// - /// As noted above, `timeframe_start` for a given cumulative datapoint is always - /// the beginning of the billing period, and `timeframe_end` is incremented one - /// day at a time to construct the response. When a timeframe is passed in that - /// is not aligned to the current subscription's billing period, the response will - /// contain cumulative totals from multiple billing periods. - /// - /// Suppose the queried customer has a subscription aligned to the 15th of every - /// month. If this endpoint is queried with the date range `2023-06-01` - `2023-07-01`, - /// the first data point will represent about half a billing period's worth of - /// costs, accounting for accruals from the start of the billing period and inclusive - /// of the first day of the timeframe (`timeframe_start = 2023-05-15 00:00:00`, - /// `timeframe_end = 2023-06-02 00:00:00`) - /// - /// | datapoint index | timeframe_start | timeframe_end | | ----------- | -----------| - /// ----------- | | 0 | 2023-05-15 | 2023-06-02 | | 1 | 2023-05-15 | 2023-06-03 - /// | | 2 | ... | ... | | 3 | 2023-05-15 | 2023-06-14 | | 4 | 2023-06-15 | 2023-06-16 - /// | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 | 2023-07-01 | - /// - /// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). - /// - /// ### Matrix prices When a price uses matrix pricing, it's important to view - /// costs grouped by those matrix dimensions. Orb will return `price_groups` with - /// the `grouping_key` and `secondary_grouping_key` based on the matrix price definition, - /// for each `grouping_value` and `secondary_grouping_value` available. - /// - Tasks::Task List(Costs::CostListParams @params); - - /// - /// This endpoint is used to fetch a day-by-day snapshot of a customer's costs - /// in Orb, calculated by applying pricing information to the underlying usage (see - /// the [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) - /// to fetch usage per metric, in usage units rather than a currency). - /// - /// This endpoint can be leveraged for internal tooling and to provide a more transparent - /// billing experience for your end users: - /// - /// 1. Understand the cost breakdown per line item historically and in real-time - /// for the current billing period. 2. Provide customer visibility into how different - /// services are contributing to the overall invoice with a per-day timeseries - /// (as compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) - /// resource, which represents a snapshot for the current period). 3. Assess how - /// minimums and discounts affect your customers by teasing apart costs directly - /// as a result of usage, as opposed to minimums and discounts at the plan and - /// price level. 4. Gain insight into key customer health metrics, such as the percent - /// utilization of the minimum committed spend. - /// - /// ## Fetching subscriptions By default, this endpoint fetches the currently active - /// subscription for the customer, and returns cost information for the subscription's - /// current billing period, broken down by each participating price. If there are - /// no currently active subscriptions, this will instead default to the most recently - /// active subscription or return an empty series if none are found. For example, - /// if your plan charges for compute hours, job runs, and data syncs, then this - /// endpoint would provide a daily breakdown of your customer's cost for each of - /// those axes. - /// - /// If timeframe bounds are specified, Orb fetches all subscriptions that were - /// active in that timeframe. If two subscriptions overlap on a single day, costs - /// from each price will be summed, and prices for both subscriptions will be included - /// in the breakdown. - /// - /// ## Prepaid plans For plans that include prices which deduct credits rather than - /// accrue in-arrears charges in a billable currency, this endpoint will return - /// the total deduction amount, in credits, for the specified timeframe. - /// - /// ## Cumulative subtotals and totals Since the subtotal and total must factor - /// in any billing-period level discounts and minimums, it's most meaningful to - /// consider costs relative to the start of the subscription's billing period. As - /// a result, by default this endpoint returns cumulative totals since the beginning - /// of the billing period. In particular, the `timeframe_start` of a returned timeframe - /// window is *always* the beginning of the billing period and `timeframe_end` is - /// incremented one day at a time to build the result. - /// - /// A customer that uses a few API calls a day but has a minimum commitment might - /// exhibit the following pattern for their subtotal and total in the first few - /// days of the month. Here, we assume that each API call is \$2.50, the customer's - /// plan has a monthly minimum of \$50 for this price, and that the subscription's - /// billing period bounds are aligned to the first of the month: - /// - /// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total (incl. - /// commitment) | | -----------| ----------- | ----------- | ----------- |----------- - /// | | 2023-02-01 | 2023-02-02 | 9 | \$22.50 | \$50.00 | | 2023-02-01 | 2023-02-03 - /// | 19 | \$47.50 | \$50.00 | | 2023-02-01 | 2023-02-04 | 20 | \$50.00 | \$50.00 - /// | | 2023-02-01 | 2023-02-05 | 28 | \$70.00 | \$70.00 | | 2023-02-01 | 2023-02-06 - /// | 36 | \$90.00 | \$90.00 | - /// - /// ### Periodic values When the query parameter `view_mode=periodic` is specified, - /// Orb will return an incremental day-by-day view of costs. In this case, there - /// will always be a one-day difference between `timeframe_start` and `timeframe_end` - /// for the timeframes returned. This is a transform on top of the cumulative costs, - /// calculated by taking the difference of each timeframe with the last. Note that - /// in the above example, the `Total` value would be 0 for the second two data - /// points, since the minimum commitment has not yet been hit and each day is not - /// contributing anything to the total cost. - /// - /// ## Timeframe bounds For an active subscription, both timeframes should be specified - /// in the request. If a subscription starts or ends within the timeframe, the - /// response will only include windows where the subscription is active. If a subscription - /// has ended, no timeframe bounds need to be specified and the response will default - /// to the billing period when the subscription was last active. - /// - /// As noted above, `timeframe_start` for a given cumulative datapoint is always - /// the beginning of the billing period, and `timeframe_end` is incremented one - /// day at a time to construct the response. When a timeframe is passed in that - /// is not aligned to the current subscription's billing period, the response will - /// contain cumulative totals from multiple billing periods. - /// - /// Suppose the queried customer has a subscription aligned to the 15th of every - /// month. If this endpoint is queried with the date range `2023-06-01` - `2023-07-01`, - /// the first data point will represent about half a billing period's worth of - /// costs, accounting for accruals from the start of the billing period and inclusive - /// of the first day of the timeframe (`timeframe_start = 2023-05-15 00:00:00`, - /// `timeframe_end = 2023-06-02 00:00:00`) - /// - /// | datapoint index | timeframe_start | timeframe_end | | ----------- | -----------| - /// ----------- | | 0 | 2023-05-15 | 2023-06-02 | | 1 | 2023-05-15 | 2023-06-03 - /// | | 2 | ... | ... | | 3 | 2023-05-15 | 2023-06-14 | | 4 | 2023-06-15 | 2023-06-16 - /// | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 | 2023-07-01 | - /// - /// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). - /// - /// ### Matrix prices When a price uses matrix pricing, it's important to view - /// costs grouped by those matrix dimensions. Orb will return `price_groups` with - /// the `grouping_key` and `secondary_grouping_key` based on the matrix price definition, - /// for each `grouping_value` and `secondary_grouping_value` available. - /// - Tasks::Task ListByExternalID( - Costs::CostListByExternalIDParams @params - ); -} diff --git a/src/Orb/Service/Customers/Credits/CreditService.cs b/src/Orb/Service/Customers/Credits/CreditService.cs deleted file mode 100644 index 83efb9da..00000000 --- a/src/Orb/Service/Customers/Credits/CreditService.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Credits = Orb.Models.Customers.Credits; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Ledger = Orb.Service.Customers.Credits.Ledger; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; -using TopUps = Orb.Service.Customers.Credits.TopUps; - -namespace Orb.Service.Customers.Credits; - -public sealed class CreditService : ICreditService -{ - readonly Orb::IOrbClient _client; - - public CreditService(Orb::IOrbClient client) - { - _client = client; - _ledger = new(() => new Ledger::LedgerService(client)); - _topUps = new(() => new TopUps::TopUpService(client)); - } - - readonly System::Lazy _ledger; - public Ledger::ILedgerService Ledger - { - get { return _ledger.Value; } - } - - readonly System::Lazy _topUps; - public TopUps::ITopUpService TopUps - { - get { return _topUps.Value; } - } - - public async Tasks::Task List( - Credits::CreditListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task ListByExternalID( - Credits::CreditListByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Customers/Credits/ICreditService.cs b/src/Orb/Service/Customers/Credits/ICreditService.cs deleted file mode 100644 index c35cb37f..00000000 --- a/src/Orb/Service/Customers/Credits/ICreditService.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Credits = Orb.Models.Customers.Credits; -using Ledger = Orb.Service.Customers.Credits.Ledger; -using Tasks = System.Threading.Tasks; -using TopUps = Orb.Service.Customers.Credits.TopUps; - -namespace Orb.Service.Customers.Credits; - -public interface ICreditService -{ - Ledger::ILedgerService Ledger { get; } - - TopUps::ITopUpService TopUps { get; } - - /// - /// Returns a paginated list of unexpired, non-zero credit blocks for a customer. - /// - /// If `include_all_blocks` is set to `true`, all credit blocks (including expired - /// and depleted blocks) will be included in the response. - /// - /// Note that `currency` defaults to credits if not specified. To use a real world - /// currency, set `currency` to an ISO 4217 string. - /// - Tasks::Task List(Credits::CreditListParams @params); - - /// - /// Returns a paginated list of unexpired, non-zero credit blocks for a customer. - /// - /// If `include_all_blocks` is set to `true`, all credit blocks (including expired - /// and depleted blocks) will be included in the response. - /// - /// Note that `currency` defaults to credits if not specified. To use a real world - /// currency, set `currency` to an ISO 4217 string. - /// - Tasks::Task ListByExternalID( - Credits::CreditListByExternalIDParams @params - ); -} diff --git a/src/Orb/Service/Customers/Credits/Ledger/ILedgerService.cs b/src/Orb/Service/Customers/Credits/Ledger/ILedgerService.cs deleted file mode 100644 index 7de67afc..00000000 --- a/src/Orb/Service/Customers/Credits/Ledger/ILedgerService.cs +++ /dev/null @@ -1,321 +0,0 @@ -using Ledger = Orb.Models.Customers.Credits.Ledger; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers.Credits.Ledger; - -public interface ILedgerService -{ - /// - /// The credits ledger provides _auditing_ functionality over Orb's credits system - /// with a list of actions that have taken place to modify a customer's credit balance. - /// This [paginated endpoint](/api-reference/pagination) lists these entries, starting - /// from the most recent ledger entry. - /// - /// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). - /// - /// There are four major types of modifications to credit balance, detailed below. - /// - /// ## Increment Credits (which optionally expire on a future date) can be added - /// via the API ([Add Ledger Entry](create-ledger-entry)). The ledger entry for - /// such an action will always contain the total eligible starting and ending balance - /// for the customer at the time the entry was added to the ledger. - /// - /// ## Decrement Deductions can occur as a result of an API call to create a ledger - /// entry (see [Add Ledger Entry](create-ledger-entry)), or automatically as a - /// result of incurring usage. Both ledger entries present the `decrement` entry type. - /// - /// As usage for a customer is reported into Orb, credits may be deducted according - /// to the customer's plan configuration. An automated deduction of this type will - /// result in a ledger entry, also with a starting and ending balance. In order - /// to provide better tracing capabilities for automatic deductions, Orb always - /// associates each automatic deduction with the `event_id` at the time of ingestion, - /// used to pinpoint _why_ credit deduction took place and to ensure that credits - /// are never deducted without an associated usage event. - /// - /// By default, Orb uses an algorithm that automatically deducts from the *soonest - /// expiring credit block* first in order to ensure that all credits are utilized - /// appropriately. As an example, if trial credits with an expiration date of 2 - /// weeks from now are present for a customer, they will be used before any deductions - /// take place from a non-expiring credit block. - /// - /// If there are multiple blocks with the same expiration date, Orb will deduct - /// from the block with the *lower cost basis* first (e.g. trial credits with a - /// \$0 cost basis before paid credits with a \$5.00 cost basis). - /// - /// It's also possible for a single usage event's deduction to _span_ credit blocks. - /// In this case, Orb will deduct from the next block, ending at the credit block - /// which consists of unexpiring credits. Each of these deductions will lead to - /// a _separate_ ledger entry, one per credit block that is deducted from. By default, - /// the customer's total credit balance in Orb can be negative as a result of a decrement. - /// - /// ## Expiration change The expiry of credits can be changed as a result of the - /// API (See [Add Ledger Entry](create-ledger-entry)). This will create a ledger - /// entry that specifies the balance as well as the initial and target expiry dates. - /// - /// Note that for this entry type, `starting_balance` will equal `ending_balance`, - /// and the `amount` represents the balance transferred. The credit block linked - /// to the ledger entry is the source credit block from which there was an expiration change - /// - /// ## Credits expiry When a set of credits expire on pre-set expiration date, - /// the customer's balance automatically reflects this change and adds an entry - /// to the ledger indicating this event. Note that credit expiry should always happen - /// close to a date boundary in the customer's timezone. - /// - /// ## Void initiated Credit blocks can be voided via the API. The `amount` on this - /// entry corresponds to the number of credits that were remaining in the block - /// at time of void. `void_reason` will be populated if the void is created with - /// a reason. - /// - /// ## Void When a set of credits is voided, the customer's balance automatically - /// reflects this change and adds an entry to the ledger indicating this event. - /// - /// ## Amendment When credits are added to a customer's balance as a result of a - /// correction, this entry will be added to the ledger to indicate the adjustment - /// of credits. - /// - Tasks::Task List(Ledger::LedgerListParams @params); - - /// - /// This endpoint allows you to create a new ledger entry for a specified customer's - /// balance. This can be used to increment balance, deduct credits, and change the - /// expiry date of existing credits. - /// - /// ## Effects of adding a ledger entry 1. After calling this endpoint, [Fetch - /// Credit Balance](fetch-customer-credits) will return a credit block that represents - /// the changes (i.e. balance changes or transfers). 2. A ledger entry will be - /// added to the credits ledger for this customer, and therefore returned in the - /// [View Credits Ledger](fetch-customer-credits-ledger) response as well as - /// serialized in the response to this request. In the case of deductions without - /// a specified block, multiple ledger entries may be created if the deduction spans - /// credit blocks. 3. If `invoice_settings` is specified, an invoice will be created - /// that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). - /// - /// ## Adding credits Adding credits is done by creating an entry of type `increment`. - /// This requires the caller to specify a number of credits as well as an optional - /// expiry date in `YYYY-MM-DD` format. Orb also recommends specifying a description - /// to assist with auditing. When adding credits, the caller can also specify - /// a cost basis per-credit, to indicate how much in USD a customer paid for a - /// single credit in a block. This can later be used for revenue recognition. - /// - /// The following snippet illustrates a sample request body to increment credits - /// which will expire in January of 2022. - /// - /// ```json { "entry_type": "increment", "amount": 100, "expiry_date": "2022-12-28", - /// "per_unit_cost_basis": "0.20", "description": "Purchased 100 credits" } ``` - /// - /// Note that by default, Orb will always first increment any _negative_ balance - /// in existing blocks before adding the remaining amount to the desired credit block. - /// - /// ### Invoicing for credits By default, Orb manipulates the credit ledger but - /// does not charge for credits. However, if you pass `invoice_settings` in the - /// body of this request, Orb will also generate a one-off invoice for the customer - /// for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, - /// since the total charges on the invoice are calculated by multiplying the cost - /// basis with the number of credit units added. - /// - /// ## Deducting Credits Orb allows you to deduct credits from a customer by creating - /// an entry of type `decrement`. Orb matches the algorithm for automatic deductions - /// for determining which credit blocks to decrement from. In the case that the - /// deduction leads to multiple ledger entries, the response from this endpoint - /// will be the final deduction. Orb also optionally allows specifying a description - /// to assist with auditing. - /// - /// The following snippet illustrates a sample request body to decrement credits. - /// - /// ```json { "entry_type": "decrement", "amount": 20, "description": "Removing - /// excess credits" } ``` - /// - /// ## Changing credits expiry If you'd like to change when existing credits expire, - /// you should create a ledger entry of type `expiration_change`. For this entry, - /// the required parameter `expiry_date` identifies the _originating_ block, and - /// the required parameter `target_expiry_date` identifies when the transferred - /// credits should now expire. A new credit block will be created with expiry date - /// `target_expiry_date`, with the same cost basis data as the original credit - /// block, if present. - /// - /// Note that the balance of the block with the given `expiry_date` must be at least - /// equal to the desired transfer amount determined by the `amount` parameter. - /// - /// The following snippet illustrates a sample request body to extend the expiration - /// date of credits by one year: - /// - /// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": - /// "2022-12-28", "block_id": "UiUhFWeLHPrBY4Ad", "target_expiry_date": "2023-12-28", - /// "description": "Extending credit validity" } ``` - /// - /// ## Voiding credits - /// - /// If you'd like to void a credit block, create a ledger entry of type `void`. - /// For this entry, `block_id` is required to identify the block, and `amount` - /// indicates how many credits to void, up to the block's initial balance. Pass - /// in a `void_reason` of `refund` if the void is due to a refund. - /// - /// ## Amendment - /// - /// If you'd like to undo a decrement on a credit block, create a ledger entry - /// of type `amendment`. For this entry, `block_id` is required to identify the - /// block that was originally decremented from, and `amount` indicates how many - /// credits to return to the customer, up to the block's initial balance. - /// - Tasks::Task CreateEntry( - Ledger::LedgerCreateEntryParams @params - ); - - /// - /// This endpoint allows you to create a new ledger entry for a specified customer's - /// balance. This can be used to increment balance, deduct credits, and change the - /// expiry date of existing credits. - /// - /// ## Effects of adding a ledger entry 1. After calling this endpoint, [Fetch - /// Credit Balance](fetch-customer-credits) will return a credit block that represents - /// the changes (i.e. balance changes or transfers). 2. A ledger entry will be - /// added to the credits ledger for this customer, and therefore returned in the - /// [View Credits Ledger](fetch-customer-credits-ledger) response as well as - /// serialized in the response to this request. In the case of deductions without - /// a specified block, multiple ledger entries may be created if the deduction spans - /// credit blocks. 3. If `invoice_settings` is specified, an invoice will be created - /// that reflects the cost of the credits (based on `amount` and `per_unit_cost_basis`). - /// - /// ## Adding credits Adding credits is done by creating an entry of type `increment`. - /// This requires the caller to specify a number of credits as well as an optional - /// expiry date in `YYYY-MM-DD` format. Orb also recommends specifying a description - /// to assist with auditing. When adding credits, the caller can also specify - /// a cost basis per-credit, to indicate how much in USD a customer paid for a - /// single credit in a block. This can later be used for revenue recognition. - /// - /// The following snippet illustrates a sample request body to increment credits - /// which will expire in January of 2022. - /// - /// ```json { "entry_type": "increment", "amount": 100, "expiry_date": "2022-12-28", - /// "per_unit_cost_basis": "0.20", "description": "Purchased 100 credits" } ``` - /// - /// Note that by default, Orb will always first increment any _negative_ balance - /// in existing blocks before adding the remaining amount to the desired credit block. - /// - /// ### Invoicing for credits By default, Orb manipulates the credit ledger but - /// does not charge for credits. However, if you pass `invoice_settings` in the - /// body of this request, Orb will also generate a one-off invoice for the customer - /// for the credits pre-purchase. Note that you _must_ provide the `per_unit_cost_basis`, - /// since the total charges on the invoice are calculated by multiplying the cost - /// basis with the number of credit units added. - /// - /// ## Deducting Credits Orb allows you to deduct credits from a customer by creating - /// an entry of type `decrement`. Orb matches the algorithm for automatic deductions - /// for determining which credit blocks to decrement from. In the case that the - /// deduction leads to multiple ledger entries, the response from this endpoint - /// will be the final deduction. Orb also optionally allows specifying a description - /// to assist with auditing. - /// - /// The following snippet illustrates a sample request body to decrement credits. - /// - /// ```json { "entry_type": "decrement", "amount": 20, "description": "Removing - /// excess credits" } ``` - /// - /// ## Changing credits expiry If you'd like to change when existing credits expire, - /// you should create a ledger entry of type `expiration_change`. For this entry, - /// the required parameter `expiry_date` identifies the _originating_ block, and - /// the required parameter `target_expiry_date` identifies when the transferred - /// credits should now expire. A new credit block will be created with expiry date - /// `target_expiry_date`, with the same cost basis data as the original credit - /// block, if present. - /// - /// Note that the balance of the block with the given `expiry_date` must be at least - /// equal to the desired transfer amount determined by the `amount` parameter. - /// - /// The following snippet illustrates a sample request body to extend the expiration - /// date of credits by one year: - /// - /// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": - /// "2022-12-28", "block_id": "UiUhFWeLHPrBY4Ad", "target_expiry_date": "2023-12-28", - /// "description": "Extending credit validity" } ``` - /// - /// ## Voiding credits - /// - /// If you'd like to void a credit block, create a ledger entry of type `void`. - /// For this entry, `block_id` is required to identify the block, and `amount` - /// indicates how many credits to void, up to the block's initial balance. Pass - /// in a `void_reason` of `refund` if the void is due to a refund. - /// - /// ## Amendment - /// - /// If you'd like to undo a decrement on a credit block, create a ledger entry - /// of type `amendment`. For this entry, `block_id` is required to identify the - /// block that was originally decremented from, and `amount` indicates how many - /// credits to return to the customer, up to the block's initial balance. - /// - Tasks::Task CreateEntryByExternalID( - Ledger::LedgerCreateEntryByExternalIDParams @params - ); - - /// - /// The credits ledger provides _auditing_ functionality over Orb's credits system - /// with a list of actions that have taken place to modify a customer's credit balance. - /// This [paginated endpoint](/api-reference/pagination) lists these entries, starting - /// from the most recent ledger entry. - /// - /// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). - /// - /// There are four major types of modifications to credit balance, detailed below. - /// - /// ## Increment Credits (which optionally expire on a future date) can be added - /// via the API ([Add Ledger Entry](create-ledger-entry)). The ledger entry for - /// such an action will always contain the total eligible starting and ending balance - /// for the customer at the time the entry was added to the ledger. - /// - /// ## Decrement Deductions can occur as a result of an API call to create a ledger - /// entry (see [Add Ledger Entry](create-ledger-entry)), or automatically as a - /// result of incurring usage. Both ledger entries present the `decrement` entry type. - /// - /// As usage for a customer is reported into Orb, credits may be deducted according - /// to the customer's plan configuration. An automated deduction of this type will - /// result in a ledger entry, also with a starting and ending balance. In order - /// to provide better tracing capabilities for automatic deductions, Orb always - /// associates each automatic deduction with the `event_id` at the time of ingestion, - /// used to pinpoint _why_ credit deduction took place and to ensure that credits - /// are never deducted without an associated usage event. - /// - /// By default, Orb uses an algorithm that automatically deducts from the *soonest - /// expiring credit block* first in order to ensure that all credits are utilized - /// appropriately. As an example, if trial credits with an expiration date of 2 - /// weeks from now are present for a customer, they will be used before any deductions - /// take place from a non-expiring credit block. - /// - /// If there are multiple blocks with the same expiration date, Orb will deduct - /// from the block with the *lower cost basis* first (e.g. trial credits with a - /// \$0 cost basis before paid credits with a \$5.00 cost basis). - /// - /// It's also possible for a single usage event's deduction to _span_ credit blocks. - /// In this case, Orb will deduct from the next block, ending at the credit block - /// which consists of unexpiring credits. Each of these deductions will lead to - /// a _separate_ ledger entry, one per credit block that is deducted from. By default, - /// the customer's total credit balance in Orb can be negative as a result of a decrement. - /// - /// ## Expiration change The expiry of credits can be changed as a result of the - /// API (See [Add Ledger Entry](create-ledger-entry)). This will create a ledger - /// entry that specifies the balance as well as the initial and target expiry dates. - /// - /// Note that for this entry type, `starting_balance` will equal `ending_balance`, - /// and the `amount` represents the balance transferred. The credit block linked - /// to the ledger entry is the source credit block from which there was an expiration change - /// - /// ## Credits expiry When a set of credits expire on pre-set expiration date, - /// the customer's balance automatically reflects this change and adds an entry - /// to the ledger indicating this event. Note that credit expiry should always happen - /// close to a date boundary in the customer's timezone. - /// - /// ## Void initiated Credit blocks can be voided via the API. The `amount` on this - /// entry corresponds to the number of credits that were remaining in the block - /// at time of void. `void_reason` will be populated if the void is created with - /// a reason. - /// - /// ## Void When a set of credits is voided, the customer's balance automatically - /// reflects this change and adds an entry to the ledger indicating this event. - /// - /// ## Amendment When credits are added to a customer's balance as a result of a - /// correction, this entry will be added to the ledger to indicate the adjustment - /// of credits. - /// - Tasks::Task ListByExternalID( - Ledger::LedgerListByExternalIDParams @params - ); -} diff --git a/src/Orb/Service/Customers/Credits/Ledger/LedgerService.cs b/src/Orb/Service/Customers/Credits/Ledger/LedgerService.cs deleted file mode 100644 index 4dd8c51a..00000000 --- a/src/Orb/Service/Customers/Credits/Ledger/LedgerService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Ledger = Orb.Models.Customers.Credits.Ledger; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers.Credits.Ledger; - -public sealed class LedgerService : ILedgerService -{ - readonly Orb::IOrbClient _client; - - public LedgerService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task List(Ledger::LedgerListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task CreateEntry( - Ledger::LedgerCreateEntryParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task CreateEntryByExternalID( - Ledger::LedgerCreateEntryByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task ListByExternalID( - Ledger::LedgerListByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Customers/Credits/TopUps/ITopUpService.cs b/src/Orb/Service/Customers/Credits/TopUps/ITopUpService.cs deleted file mode 100644 index a908b033..00000000 --- a/src/Orb/Service/Customers/Credits/TopUps/ITopUpService.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Tasks = System.Threading.Tasks; -using TopUps = Orb.Models.Customers.Credits.TopUps; - -namespace Orb.Service.Customers.Credits.TopUps; - -public interface ITopUpService -{ - /// - /// This endpoint allows you to create a new top-up for a specified customer's - /// balance. While this top-up is active, the customer's balance will added in - /// increments of the specified amount whenever the balance reaches the specified threshold. - /// - /// If a top-up already exists for this customer in the same currency, the existing - /// top-up will be replaced. - /// - Tasks::Task Create(TopUps::TopUpCreateParams @params); - - /// - /// List top-ups - /// - Tasks::Task List(TopUps::TopUpListParams @params); - - /// - /// This deactivates the top-up and voids any invoices associated with pending - /// credit blocks purchased through the top-up. - /// - Tasks::Task Delete(TopUps::TopUpDeleteParams @params); - - /// - /// This endpoint allows you to create a new top-up for a specified customer's - /// balance. While this top-up is active, the customer's balance will added in - /// increments of the specified amount whenever the balance reaches the specified threshold. - /// - /// If a top-up already exists for this customer in the same currency, the existing - /// top-up will be replaced. - /// - Tasks::Task CreateByExternalID( - TopUps::TopUpCreateByExternalIDParams @params - ); - - /// - /// This deactivates the top-up and voids any invoices associated with pending - /// credit blocks purchased through the top-up. - /// - Tasks::Task DeleteByExternalID(TopUps::TopUpDeleteByExternalIDParams @params); - - /// - /// List top-ups by external ID - /// - Tasks::Task ListByExternalID( - TopUps::TopUpListByExternalIDParams @params - ); -} diff --git a/src/Orb/Service/Customers/Credits/TopUps/TopUpService.cs b/src/Orb/Service/Customers/Credits/TopUps/TopUpService.cs deleted file mode 100644 index 0f5ff9cc..00000000 --- a/src/Orb/Service/Customers/Credits/TopUps/TopUpService.cs +++ /dev/null @@ -1,136 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; -using TopUps = Orb.Models.Customers.Credits.TopUps; - -namespace Orb.Service.Customers.Credits.TopUps; - -public sealed class TopUpService : ITopUpService -{ - readonly Orb::IOrbClient _client; - - public TopUpService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create(TopUps::TopUpCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List(TopUps::TopUpListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Delete(TopUps::TopUpDeleteParams @params) - { - Http::HttpRequestMessage webRequest = new( - Http::HttpMethod.Delete, - @params.Url(this._client) - ); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - } - - public async Tasks::Task CreateByExternalID( - TopUps::TopUpCreateByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task DeleteByExternalID(TopUps::TopUpDeleteByExternalIDParams @params) - { - Http::HttpRequestMessage webRequest = new( - Http::HttpMethod.Delete, - @params.Url(this._client) - ); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - } - - public async Tasks::Task ListByExternalID( - TopUps::TopUpListByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Customers/CustomerService.cs b/src/Orb/Service/Customers/CustomerService.cs deleted file mode 100644 index d5515136..00000000 --- a/src/Orb/Service/Customers/CustomerService.cs +++ /dev/null @@ -1,218 +0,0 @@ -using BalanceTransactions = Orb.Service.Customers.BalanceTransactions; -using Costs = Orb.Service.Customers.Costs; -using Credits = Orb.Service.Customers.Credits; -using Customers = Orb.Models.Customers; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers; - -public sealed class CustomerService : ICustomerService -{ - readonly Orb::IOrbClient _client; - - public CustomerService(Orb::IOrbClient client) - { - _client = client; - _costs = new(() => new Costs::CostService(client)); - _credits = new(() => new Credits::CreditService(client)); - _balanceTransactions = new(() => new BalanceTransactions::BalanceTransactionService(client) - ); - } - - readonly System::Lazy _costs; - public Costs::ICostService Costs - { - get { return _costs.Value; } - } - - readonly System::Lazy _credits; - public Credits::ICreditService Credits - { - get { return _credits.Value; } - } - - readonly System::Lazy _balanceTransactions; - public BalanceTransactions::IBalanceTransactionService BalanceTransactions - { - get { return _balanceTransactions.Value; } - } - - public async Tasks::Task Create(Customers::CustomerCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Customers::CustomerUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - Customers::CustomerListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Delete(Customers::CustomerDeleteParams @params) - { - Http::HttpRequestMessage webRequest = new( - Http::HttpMethod.Delete, - @params.Url(this._client) - ); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - } - - public async Tasks::Task Fetch(Customers::CustomerFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchByExternalID( - Customers::CustomerFetchByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task SyncPaymentMethodsFromGateway( - Customers::CustomerSyncPaymentMethodsFromGatewayParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - } - - public async Tasks::Task SyncPaymentMethodsFromGatewayByExternalCustomerID( - Customers::CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - } - - public async Tasks::Task UpdateByExternalID( - Customers::CustomerUpdateByExternalIDParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Customers/ICustomerService.cs b/src/Orb/Service/Customers/ICustomerService.cs deleted file mode 100644 index f170e2a3..00000000 --- a/src/Orb/Service/Customers/ICustomerService.cs +++ /dev/null @@ -1,115 +0,0 @@ -using BalanceTransactions = Orb.Service.Customers.BalanceTransactions; -using Costs = Orb.Service.Customers.Costs; -using Credits = Orb.Service.Customers.Credits; -using Customers = Orb.Models.Customers; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Customers; - -public interface ICustomerService -{ - Costs::ICostService Costs { get; } - - Credits::ICreditService Credits { get; } - - BalanceTransactions::IBalanceTransactionService BalanceTransactions { get; } - - /// - /// This operation is used to create an Orb customer, who is party to the core - /// billing relationship. See [Customer](/core-concepts##customer) for an overview - /// of the customer resource. - /// - /// This endpoint is critical in the following Orb functionality: * Automated charges - /// can be configured by setting `payment_provider` and `payment_provider_id` to - /// automatically issue invoices * [Customer ID Aliases](/events-and-metrics/customer-aliases) - /// can be configured by setting `external_customer_id` * [Timezone localization](/essentials/timezones) - /// can be configured on a per-customer basis by setting the `timezone` parameter - /// - Tasks::Task Create(Customers::CustomerCreateParams @params); - - /// - /// This endpoint can be used to update the `payment_provider`, `payment_provider_id`, - /// `name`, `email`, `email_delivery`, `tax_id`, `auto_collection`, `metadata`, - /// `shipping_address`, `billing_address`, and `additional_emails` of an existing - /// customer. Other fields on a customer are currently immutable. - /// - Tasks::Task Update(Customers::CustomerUpdateParams @params); - - /// - /// This endpoint returns a list of all customers for an account. The list of customers - /// is ordered starting from the most recently created customer. This endpoint follows - /// Orb's [standardized pagination format](/api-reference/pagination). - /// - /// See [Customer](/core-concepts##customer) for an overview of the customer model. - /// - Tasks::Task List(Customers::CustomerListParams @params); - - /// - /// This performs a deletion of this customer, its subscriptions, and its invoices, - /// provided the customer does not have any issued invoices. Customers with issued - /// invoices cannot be deleted. This operation is irreversible. Note that this - /// is a _soft_ deletion, but the data will be inaccessible through the API and - /// Orb dashboard. - /// - /// For a hard-deletion, please reach out to the Orb team directly. - /// - /// **Note**: This operation happens asynchronously and can be expected to take - /// a few minutes to propagate to related resources. However, querying for the - /// customer on subsequent GET requests while deletion is in process will reflect - /// its deletion. - /// - Tasks::Task Delete(Customers::CustomerDeleteParams @params); - - /// - /// This endpoint is used to fetch customer details given an identifier. If the - /// `Customer` is in the process of being deleted, only the properties `id` and - /// `deleted: true` will be returned. - /// - /// See the [Customer resource](/core-concepts#customer) for a full discussion of - /// the Customer model. - /// - Tasks::Task Fetch(Customers::CustomerFetchParams @params); - - /// - /// This endpoint is used to fetch customer details given an `external_customer_id` - /// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). - /// - /// Note that the resource and semantics of this endpoint exactly mirror [Get Customer](fetch-customer). - /// - Tasks::Task FetchByExternalID( - Customers::CustomerFetchByExternalIDParams @params - ); - - /// - /// Sync Orb's payment methods for the customer with their gateway. - /// - /// This method can be called before taking an action that may cause the customer - /// to be charged, ensuring that the most up-to-date payment method is charged. - /// - /// **Note**: This functionality is currently only available for Stripe. - /// - Tasks::Task SyncPaymentMethodsFromGateway( - Customers::CustomerSyncPaymentMethodsFromGatewayParams @params - ); - - /// - /// Sync Orb's payment methods for the customer with their gateway. - /// - /// This method can be called before taking an action that may cause the customer - /// to be charged, ensuring that the most up-to-date payment method is charged. - /// - /// **Note**: This functionality is currently only available for Stripe. - /// - Tasks::Task SyncPaymentMethodsFromGatewayByExternalCustomerID( - Customers::CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams @params - ); - - /// - /// This endpoint is used to update customer details given an `external_customer_id` - /// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that - /// the resource and semantics of this endpoint exactly mirror [Update Customer](update-customer). - /// - Tasks::Task UpdateByExternalID( - Customers::CustomerUpdateByExternalIDParams @params - ); -} diff --git a/src/Orb/Service/DimensionalPriceGroups/DimensionalPriceGroupService.cs b/src/Orb/Service/DimensionalPriceGroups/DimensionalPriceGroupService.cs deleted file mode 100644 index 96ef3a07..00000000 --- a/src/Orb/Service/DimensionalPriceGroups/DimensionalPriceGroupService.cs +++ /dev/null @@ -1,91 +0,0 @@ -using DimensionalPriceGroups = Orb.Models.DimensionalPriceGroups; -using ExternalDimensionalPriceGroupID = Orb.Service.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.DimensionalPriceGroups; - -public sealed class DimensionalPriceGroupService : IDimensionalPriceGroupService -{ - readonly Orb::IOrbClient _client; - - public DimensionalPriceGroupService(Orb::IOrbClient client) - { - _client = client; - _externalDimensionalPriceGroupID = new(() => - new ExternalDimensionalPriceGroupID::ExternalDimensionalPriceGroupIDService(client) - ); - } - - readonly System::Lazy _externalDimensionalPriceGroupID; - public ExternalDimensionalPriceGroupID::IExternalDimensionalPriceGroupIDService ExternalDimensionalPriceGroupID - { - get { return _externalDimensionalPriceGroupID.Value; } - } - - public async Tasks::Task Create( - DimensionalPriceGroups::DimensionalPriceGroupCreateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Retrieve( - DimensionalPriceGroups::DimensionalPriceGroupRetrieveParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - DimensionalPriceGroups::DimensionalPriceGroupListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDService.cs b/src/Orb/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDService.cs deleted file mode 100644 index 1698f482..00000000 --- a/src/Orb/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/ExternalDimensionalPriceGroupIDService.cs +++ /dev/null @@ -1,39 +0,0 @@ -using DimensionalPriceGroups = Orb.Models.DimensionalPriceGroups; -using ExternalDimensionalPriceGroupID = Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; - -public sealed class ExternalDimensionalPriceGroupIDService : IExternalDimensionalPriceGroupIDService -{ - readonly Orb::IOrbClient _client; - - public ExternalDimensionalPriceGroupIDService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Retrieve( - ExternalDimensionalPriceGroupID::ExternalDimensionalPriceGroupIDRetrieveParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/IExternalDimensionalPriceGroupIDService.cs b/src/Orb/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/IExternalDimensionalPriceGroupIDService.cs deleted file mode 100644 index c7f3740a..00000000 --- a/src/Orb/Service/DimensionalPriceGroups/ExternalDimensionalPriceGroupID/IExternalDimensionalPriceGroupIDService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using DimensionalPriceGroups = Orb.Models.DimensionalPriceGroups; -using ExternalDimensionalPriceGroupID = Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; - -public interface IExternalDimensionalPriceGroupIDService -{ - /// - /// Fetch dimensional price group by external ID - /// - Tasks::Task Retrieve( - ExternalDimensionalPriceGroupID::ExternalDimensionalPriceGroupIDRetrieveParams @params - ); -} diff --git a/src/Orb/Service/DimensionalPriceGroups/IDimensionalPriceGroupService.cs b/src/Orb/Service/DimensionalPriceGroups/IDimensionalPriceGroupService.cs deleted file mode 100644 index 743e6bf5..00000000 --- a/src/Orb/Service/DimensionalPriceGroups/IDimensionalPriceGroupService.cs +++ /dev/null @@ -1,38 +0,0 @@ -using DimensionalPriceGroups = Orb.Models.DimensionalPriceGroups; -using ExternalDimensionalPriceGroupID = Orb.Service.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.DimensionalPriceGroups; - -public interface IDimensionalPriceGroupService -{ - ExternalDimensionalPriceGroupID::IExternalDimensionalPriceGroupIDService ExternalDimensionalPriceGroupID { get; } - - /// - /// A dimensional price group is used to partition the result of a billable metric - /// by a set of dimensions. Prices in a price group must specify the parition used - /// to derive their usage. - /// - /// For example, suppose we have a billable metric that measures the number of - /// widgets used and we want to charge differently depending on the color of the - /// widget. We can create a price group with a dimension "color" and two prices: - /// one that charges \$10 per red widget and one that charges \$20 per blue widget. - /// - Tasks::Task Create( - DimensionalPriceGroups::DimensionalPriceGroupCreateParams @params - ); - - /// - /// Fetch dimensional price group - /// - Tasks::Task Retrieve( - DimensionalPriceGroups::DimensionalPriceGroupRetrieveParams @params - ); - - /// - /// List dimensional price groups - /// - Tasks::Task List( - DimensionalPriceGroups::DimensionalPriceGroupListParams @params - ); -} diff --git a/src/Orb/Service/Events/Backfills/BackfillService.cs b/src/Orb/Service/Events/Backfills/BackfillService.cs deleted file mode 100644 index 480f64b8..00000000 --- a/src/Orb/Service/Events/Backfills/BackfillService.cs +++ /dev/null @@ -1,121 +0,0 @@ -using Backfills = Orb.Models.Events.Backfills; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Events.Backfills; - -public sealed class BackfillService : IBackfillService -{ - readonly Orb::IOrbClient _client; - - public BackfillService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create( - Backfills::BackfillCreateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - Backfills::BackfillListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Close( - Backfills::BackfillCloseParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch( - Backfills::BackfillFetchParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Revert( - Backfills::BackfillRevertParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Events/Backfills/IBackfillService.cs b/src/Orb/Service/Events/Backfills/IBackfillService.cs deleted file mode 100644 index 39125ccc..00000000 --- a/src/Orb/Service/Events/Backfills/IBackfillService.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Backfills = Orb.Models.Events.Backfills; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Events.Backfills; - -public interface IBackfillService -{ - /// - /// Creating the backfill enables adding or replacing past events, even those that - /// are older than the ingestion grace period. Performing a backfill in Orb involves - /// 3 steps: - /// - /// 1. Create the backfill, specifying its parameters. 2. [Ingest](ingest) usage - /// events, referencing the backfill (query parameter `backfill_id`). 3. [Close](close-backfill) - /// the backfill, propagating the update in past usage throughout Orb. - /// - /// Changes from a backfill are not reflected until the backfill is closed, so - /// you won’t need to worry about your customers seeing partially updated usage - /// data. Backfills are also reversible, so you’ll be able to revert a backfill - /// if you’ve made a mistake. - /// - /// This endpoint will return a backfill object, which contains an `id`. That `id` - /// can then be used as the `backfill_id` query parameter to the event ingestion - /// endpoint to associate ingested events with this backfill. The effects (e.g. - /// updated usage graphs) of this backfill will not take place until the backfill - /// is closed. - /// - /// If the `replace_existing_events` is `true`, existing events in the backfill's - /// timeframe will be replaced with the newly ingested events associated with the - /// backfill. If `false`, newly ingested events will be added to the existing events. - /// - /// If a `customer_id` or `external_customer_id` is specified, the backfill will - /// only affect events for that customer. If neither is specified, the backfill - /// will affect all customers. - /// - /// When `replace_existing_events` is `true`, this indicates that existing events - /// in the timeframe should no longer be counted towards invoiced usage. In this - /// scenario, the parameter `filter` can be optionally added which enables filtering - /// using [computed properties](/extensibility/advanced-metrics#computed-properties). - /// The expressiveness of computed properties allows you to deprecate existing events - /// based on both a period of time and specific property values. - /// - Tasks::Task Create(Backfills::BackfillCreateParams @params); - - /// - /// This endpoint returns a list of all backfills in a list format. - /// - /// The list of backfills is ordered starting from the most recently created backfill. - /// The response also includes [`pagination_metadata`](/api-reference/pagination), - /// which lets the caller retrieve the next page of results if they exist. More - /// information about pagination can be found in the [Pagination-metadata schema](pagination). - /// - Tasks::Task List(Backfills::BackfillListParams @params); - - /// - /// Closing a backfill makes the updated usage visible in Orb. Upon closing a backfill, - /// Orb will asynchronously reflect the updated usage in invoice amounts and usage - /// graphs. Once all of the updates are complete, the backfill's status will transition - /// to `reflected`. - /// - Tasks::Task Close(Backfills::BackfillCloseParams @params); - - /// - /// This endpoint is used to fetch a backfill given an identifier. - /// - Tasks::Task Fetch(Backfills::BackfillFetchParams @params); - - /// - /// Reverting a backfill undoes all the effects of closing the backfill. If the - /// backfill is reflected, the status will transition to `pending_revert` while - /// the effects of the backfill are undone. Once all effects are undone, the backfill - /// will transition to `reverted`. - /// - /// If a backfill is reverted before its closed, no usage will be updated as a - /// result of the backfill and it will immediately transition to `reverted`. - /// - Tasks::Task Revert(Backfills::BackfillRevertParams @params); -} diff --git a/src/Orb/Service/Events/EventService.cs b/src/Orb/Service/Events/EventService.cs deleted file mode 100644 index 11678b04..00000000 --- a/src/Orb/Service/Events/EventService.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Backfills = Orb.Service.Events.Backfills; -using Events = Orb.Models.Events; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; -using Volume = Orb.Service.Events.Volume; - -namespace Orb.Service.Events; - -public sealed class EventService : IEventService -{ - readonly Orb::IOrbClient _client; - - public EventService(Orb::IOrbClient client) - { - _client = client; - _backfills = new(() => new Backfills::BackfillService(client)); - _volume = new(() => new Volume::VolumeService(client)); - } - - readonly System::Lazy _backfills; - public Backfills::IBackfillService Backfills - { - get { return _backfills.Value; } - } - - readonly System::Lazy _volume; - public Volume::IVolumeService Volume - { - get { return _volume.Value; } - } - - public async Tasks::Task Update(Events::EventUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Deprecate( - Events::EventDeprecateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Ingest(Events::EventIngestParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Search(Events::EventSearchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Events/IEventService.cs b/src/Orb/Service/Events/IEventService.cs deleted file mode 100644 index a873b891..00000000 --- a/src/Orb/Service/Events/IEventService.cs +++ /dev/null @@ -1,281 +0,0 @@ -using Backfills = Orb.Service.Events.Backfills; -using Events = Orb.Models.Events; -using Tasks = System.Threading.Tasks; -using Volume = Orb.Service.Events.Volume; - -namespace Orb.Service.Events; - -public interface IEventService -{ - Backfills::IBackfillService Backfills { get; } - - Volume::IVolumeService Volume { get; } - - /// - /// This endpoint is used to amend a single usage event with a given `event_id`. - /// `event_id` refers to the `idempotency_key` passed in during ingestion. The event - /// will maintain its existing `event_id` after the amendment. - /// - /// This endpoint will mark the existing event as ignored, and Orb will only use - /// the new event passed in the body of this request as the source of truth for - /// that `event_id`. Note that a single event can be amended any number of times, - /// so the same event can be overwritten in subsequent calls to this endpoint. - /// Only a single event with a given `event_id` will be considered the source of - /// truth at any given time. - /// - /// This is a powerful and audit-safe mechanism to retroactively update a single - /// event in cases where you need to: * update an event with new metadata as you - /// iterate on your pricing model * update an event based on the result of an external - /// API call (e.g. call to a payment gateway succeeded or failed) - /// - /// This amendment API is always audit-safe. The process will still retain the original - /// event, though it will be ignored for billing calculations. For auditing and - /// data fidelity purposes, Orb never overwrites or permanently deletes ingested - /// usage data. - /// - /// ## Request validation * The `timestamp` of the new event must match the `timestamp` - /// of the existing event already ingested. As with ingestion, all timestamps - /// must be sent in ISO8601 format with UTC timezone offset. * The `customer_id` - /// or `external_customer_id` of the new event must match the `customer_id` or - /// `external_customer_id` of the existing event already ingested. Exactly one - /// of `customer_id` and `external_customer_id` should be specified, and similar - /// to ingestion, the ID must identify a Customer resource within Orb. Unlike - /// ingestion, for event amendment, we strictly enforce that the Customer must be - /// in the Orb system, even during the initial integration period. We do not allow - /// updating the `Customer` an event is associated with. * Orb does not accept - /// an `idempotency_key` with the event in this endpoint, since this request is - /// by design idempotent. On retryable errors, you should retry the request and - /// assume the amendment operation has not succeeded until receipt of a 2xx. * - /// The event's `timestamp` must fall within the customer's current subscription's - /// billing period, or within the grace period of the customer's current subscription's - /// previous billing period. * By default, no more than 100 events can be amended - /// for a single customer in a 100 day period. For higher volume updates, consider - /// using the [event backfill](create-backfill) endpoint. - /// - Tasks::Task Update(Events::EventUpdateParams @params); - - /// - /// This endpoint is used to deprecate a single usage event with a given `event_id`. - /// `event_id` refers to the `idempotency_key` passed in during ingestion. - /// - /// This endpoint will mark the existing event as ignored. Note that if you attempt - /// to re-ingest an event with the same `event_id` as a deprecated event, Orb will - /// return an error. - /// - /// This is a powerful and audit-safe mechanism to retroactively deprecate a single - /// event in cases where you need to: * no longer bill for an event that was improperly - /// reported * no longer bill for an event based on the result of an external API - /// call (e.g. call to a payment gateway failed and the user should not be billed) - /// - /// If you want to only change specific properties of an event, but keep the event - /// as part of the billing calculation, use the [Amend event](amend-event) endpoint instead. - /// - /// This API is always audit-safe. The process will still retain the deprecated - /// event, though it will be ignored for billing calculations. For auditing and - /// data fidelity purposes, Orb never overwrites or permanently deletes ingested - /// usage data. - /// - /// ## Request validation * Orb does not accept an `idempotency_key` with the event - /// in this endpoint, since this request is by design idempotent. On retryable - /// errors, you should retry the request and assume the deprecation operation has - /// not succeeded until receipt of a 2xx. * The event's `timestamp` must fall - /// within the customer's current subscription's billing period, or within the - /// grace period of the customer's current subscription's previous billing period. - /// Orb does not allow deprecating events for billing periods that have already - /// invoiced customers. * The `customer_id` or the `external_customer_id` of the - /// original event ingestion request must identify a Customer resource within - /// Orb, even if this event was ingested during the initial integration period. - /// We do not allow deprecating events for customers not in the Orb system. * - /// By default, no more than 100 events can be deprecated for a single customer - /// in a 100 day period. For higher volume updates, consider using the [event - /// backfill](create-backfill) endpoint. - /// - Tasks::Task Deprecate(Events::EventDeprecateParams @params); - - /// - /// Orb's event ingestion model and API is designed around two core principles: - /// - /// 1. **Data fidelity**: The accuracy of your billing model depends on a robust - /// foundation of events. Orb's API protocol encourages usage patterns that ensure - /// that your data is consistently complete and correct. 2. **Fast integration**: - /// Sending events into Orb requires no tedious setup steps or explicit field schema - /// for your event shape, making it instant to start streaming in usage in real-time. - /// - /// ## Event shape - /// - /// Events are the starting point for all usage calculations in the system, and - /// are simple at their core: - /// - /// ```ts { // customer_id and external_customer_id are used to // attribute - /// usage to a given Customer. Exactly one of these // should be specified in - /// a given ingestion event. - /// - /// // `customer_id` is the Orb generated identifier for the Customer, // which - /// is returned from the Create customer API call. customer_id: string, - /// - /// // external_customer_id is an alternate identifier which is associated - /// // with a Customer at creation time. This is treated as an alias for // customer_id, - /// and is usually set to an identifier native to your system. external_customer_id: string, - /// - /// // A string name identifying the event, usually a usage // action. By convention, - /// this should not contain any whitespace. event_name: string, - /// - /// // An ISO 8601 format date with no timezone offset. // This should represent - /// the time that usage occurred // and is important to attribute usage to a given - /// // billing period. See the notes below on determining the timestamp. // - /// e.g. 2020-12-09T16:09:53Z timestamp: string, - /// - /// // A unique value, generated by the client, that is // used to de-duplicate - /// events. // Exactly one event with a given // idempotency key will be ingested, - /// which allows for // safe request retries. idempotency_key: string - /// - /// // Optional custom metadata to attach to the event. // This might include - /// a numeric value used for aggregation, // or a string/boolean value used for - /// filtering. // The schema of this dictionary need not be pre-declared, and - /// // properties can be added at any time. properties: { [key: string]?: - /// string | number | boolean, }, } ``` - /// - /// ## Required fields Because events streamed to Orb are meant to be as flexible - /// as possible, there are only a few required fields in every event. - /// - /// - We recommend that `idempotency_key` are unique strings that you generated - /// with V4 UUIDs, but only require that they uniquely identify an event (i.e. don’t - /// collide). - The `timestamp` field in the event body will be used to determine - /// which billable period a given event falls into. For example, with a monthly - /// billing cycle starting from the first of December, Orb will calculate metrics - /// based on events that fall into the range `12-01 00:00:00 <= timestamp < 01-01 00:00:00`. - /// - /// ## Logging metadata - /// - /// Orb allows tagging events with metadata using a flexible properties dictionary. - /// Since Orb does not enforce a rigid schema for this field-set, key-value pairs - /// can be added dynamically as your events evolve. - /// - /// This dictionary can be helpful for a wide variety of use cases: - /// - /// - Numeric properties on events like `compute_time_ms` can later be inputs to - /// our flexible query engine to determine usage. - Logging a region or cluster - /// with each event can help you provide customers more granular visibility into - /// their usage. - If you are using matrix pricing and matching a matrix price - /// key with a property, you should ensure the value for that property is sent - /// as a string. - /// - /// We encourage logging this metadata with an eye towards future use cases to - /// ensure full coverage for historical data. The datatype of the value in the properties - /// dictionary is important for metric creation from an event source. Values that - /// you wish to numerically aggregate should be of numeric type in the event. - /// - /// ## Determining event timestamp For cases where usage is being reported in real - /// time as it is occurring, timestamp should correspond to the time that usage occurred. - /// - /// In cases where usage is reported in aggregate for a historical timeframe at - /// a regular interval, we recommend setting the event `timestamp` to the midpoint - /// of the interval. As an example, if you have an hourly reporter that sends data - /// once an hour for the previous hour of usage, setting the `timestamp` to the - /// half-hour mark will ensure that the usage is counted within the correct period. - /// - /// Note that other time-related fields (e.g. time elapsed) can be added to the - /// properties dictionary as necessary. - /// - /// In cases where usage is reported in aggregate for a historical timeframe, the - /// timestamp must be within the grace period set for your account. Events with - /// `timestamp < current_time - grace_period` will not be accepted as a valid event, - /// and will throw validation errors. Enforcing the grace period enables Orb to - /// accurately map usage to the correct billing cycle and ensure that all usage - /// is billed for in the corresponding billing period. - /// - /// In general, Orb does not expect events with future dated timestamps. In cases - /// where the timestamp is at least 24 hours ahead of the current time, the event - /// will not be accepted as a valid event, and will throw validation errors. - /// - /// ## Event validation - /// - /// Orb’s validation ensures that you recognize errors in your events as quickly - /// as possible, and the API provides informative error messages to help you fix - /// problems quickly. - /// - /// We validate the following: - /// - /// - Exactly one of `customer_id` and `external_customer_id` should be specified. - /// - If the `customer_id` is specified, the customer in Orb must exist. - If the - /// `external_customer_id` is specified, the customer in Orb does not need to exist. - /// Events will be attributed to any future customers with the `external_customer_id` - /// on subscription creation. - `timestamp` must conform to ISO 8601 and represent - /// a timestamp at most 1 hour in the future. This timestamp should be sent in - /// UTC timezone (no timezone offset). - /// - /// ## Idempotency and retry semantics - /// - /// Orb's idempotency guarantees allow you to implement safe retry logic in the - /// event of network or machine failures, ensuring data fidelity. Each event in - /// the request payload is associated with an idempotency key, and Orb guarantees - /// that a single idempotency key will be successfully ingested at most once. Note - /// that when Orb encounters events with duplicate idempotency keys and differing - /// event bodies in a batch of events, the entire batch will be rejected. - /// - /// - Successful responses return a 200 HTTP status code. The response contains - /// information about previously processed events. - Requests that return a `4xx` - /// HTTP status code indicate a payload error and contain at least one event with - /// a validation failure. An event with a validation failure can be re-sent to the - /// ingestion endpoint (after the payload is fixed) with the original idempotency - /// key since that key is not marked as processed. - Requests that return a `5xx` - /// HTTP status code indicate a server-side failure. These requests should be retried - /// in their entirety. - /// - /// ## API usage and limits The ingestion API is designed made for real-time streaming - /// ingestion and architected for high throughput. Even if events are later deemed - /// unnecessary or filtered out, we encourage you to log them to Orb if they may - /// be relevant to billing calculations in the future. - /// - /// To take advantage of the real-time features of the Orb platform and avoid any - /// chance of dropped events by producers, we recommend reporting events to Orb - /// frequently. Optionally, events can also be briefly aggregated at the source, - /// as this API accepts an array of event bodies. - /// - /// Orb does not currently enforce a hard rate-limit for API usage or a maximum - /// request payload size, but please give us a heads up if you’re changing either - /// of these factors by an order of magnitude from initial setup. - /// - /// ## Testing in debug mode The ingestion API supports a debug mode, which returns - /// additional verbose output to indicate which event idempotency keys were newly - /// ingested or duplicates from previous requests. To enable this mode, mark `debug=true` - /// as a query parameter. - /// - /// If `debug=true` is not specified, the response will only contain `validation_failed`. - /// Orb will still honor the idempotency guarantees set [here](/events-and-metrics/event-ingestion#event-volume-and-concurrency) - /// in all cases. - /// - /// We strongly recommend that you only use debug mode as part of testing your initial - /// Orb integration. Once you're ready to switch to production, disable debug mode - /// to take advantage of improved performance and maximal throughput. - /// - /// #### Example: ingestion response with `debug=true` - /// - /// ```json { "debug": { "duplicate": [], "ingested": [ "B7E83HDMfJPAunXW", - /// "SJs5DQJ3TnwSqEZE", "8SivfDsNKwCeAXim" ] }, "validation_failed": - /// [] } ``` - /// - /// #### Example: ingestion response with `debug=false` - /// - /// ```json { "validation_failed": [] } ``` - /// - Tasks::Task Ingest(Events::EventIngestParams @params); - - /// - /// This endpoint returns a filtered set of events for an account in a [paginated - /// list format](/api-reference/pagination). - /// - /// Note that this is a `POST` endpoint rather than a `GET` endpoint because it - /// employs a JSON body for search criteria rather than query parameters, allowing - /// for a more flexible search syntax. - /// - /// Note that a search criteria _must_ be specified. Currently, Orb supports the - /// following criteria: - `event_ids`: This is an explicit array of IDs to filter - /// by. Note that an event's ID is the `idempotency_key` that was originally - /// used for ingestion. - /// - /// By default, Orb will not throw a `404` if no events matched, Orb will return - /// an empty array for `data` instead. - /// - Tasks::Task Search(Events::EventSearchParams @params); -} diff --git a/src/Orb/Service/Events/Volume/IVolumeService.cs b/src/Orb/Service/Events/Volume/IVolumeService.cs deleted file mode 100644 index 4e336d72..00000000 --- a/src/Orb/Service/Events/Volume/IVolumeService.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Tasks = System.Threading.Tasks; -using Volume = Orb.Models.Events.Volume; - -namespace Orb.Service.Events.Volume; - -public interface IVolumeService -{ - /// - /// This endpoint returns the event volume for an account in a [paginated list format](/api-reference/pagination). - /// - /// The event volume is aggregated by the hour and the [timestamp](/api-reference/event/ingest-events) - /// field is used to determine which hour an event is associated with. Note, this - /// means that late-arriving events increment the volume count for the hour window - /// the timestamp is in, not the latest hour window. - /// - /// Each item in the response contains the count of events aggregated by the hour - /// where the start and end time are hour-aligned and in UTC. When a specific timestamp - /// is passed in for either start or end time, the response includes the hours - /// the timestamp falls in. - /// - Tasks::Task List(Volume::VolumeListParams @params); -} diff --git a/src/Orb/Service/Events/Volume/VolumeService.cs b/src/Orb/Service/Events/Volume/VolumeService.cs deleted file mode 100644 index 7069329d..00000000 --- a/src/Orb/Service/Events/Volume/VolumeService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; -using Volume = Orb.Models.Events.Volume; - -namespace Orb.Service.Events.Volume; - -public sealed class VolumeService : IVolumeService -{ - readonly Orb::IOrbClient _client; - - public VolumeService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task List(Volume::VolumeListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/InvoiceLineItems/IInvoiceLineItemService.cs b/src/Orb/Service/InvoiceLineItems/IInvoiceLineItemService.cs deleted file mode 100644 index c0eb0a3c..00000000 --- a/src/Orb/Service/InvoiceLineItems/IInvoiceLineItemService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using InvoiceLineItems = Orb.Models.InvoiceLineItems; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.InvoiceLineItems; - -public interface IInvoiceLineItemService -{ - /// - /// This creates a one-off fixed fee invoice line item on an Invoice. This can only - /// be done for invoices that are in a `draft` status. - /// - Tasks::Task Create( - InvoiceLineItems::InvoiceLineItemCreateParams @params - ); -} diff --git a/src/Orb/Service/InvoiceLineItems/InvoiceLineItemService.cs b/src/Orb/Service/InvoiceLineItems/InvoiceLineItemService.cs deleted file mode 100644 index ec0e73bf..00000000 --- a/src/Orb/Service/InvoiceLineItems/InvoiceLineItemService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Http = System.Net.Http; -using InvoiceLineItems = Orb.Models.InvoiceLineItems; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.InvoiceLineItems; - -public sealed class InvoiceLineItemService : IInvoiceLineItemService -{ - readonly Orb::IOrbClient _client; - - public InvoiceLineItemService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create( - InvoiceLineItems::InvoiceLineItemCreateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Invoices/IInvoiceService.cs b/src/Orb/Service/Invoices/IInvoiceService.cs deleted file mode 100644 index fb7b8fad..00000000 --- a/src/Orb/Service/Invoices/IInvoiceService.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Invoices = Orb.Models.Invoices; -using Models = Orb.Models; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Invoices; - -public interface IInvoiceService -{ - /// - /// This endpoint is used to create a one-off invoice for a customer. - /// - Tasks::Task Create(Invoices::InvoiceCreateParams @params); - - /// - /// This endpoint allows you to update the `metadata` property on an invoice. If - /// you pass null for the metadata value, it will clear any existing metadata for - /// that invoice. - /// - /// `metadata` can be modified regardless of invoice state. - /// - Tasks::Task Update(Invoices::InvoiceUpdateParams @params); - - /// - /// This endpoint returns a list of all [`Invoice`](/core-concepts#invoice)s for - /// an account in a list format. - /// - /// The list of invoices is ordered starting from the most recently issued invoice - /// date. The response also includes [`pagination_metadata`](/api-reference/pagination), - /// which lets the caller retrieve the next page of results if they exist. - /// - /// By default, this only returns invoices that are `issued`, `paid`, or `synced`. - /// - /// When fetching any `draft` invoices, this returns the last-computed invoice values - /// for each draft invoice, which may not always be up-to-date since Orb regularly - /// refreshes invoices asynchronously. - /// - Tasks::Task List(Invoices::InvoiceListParams @params); - - /// - /// This endpoint is used to fetch an [`Invoice`](/core-concepts#invoice) given - /// an identifier. - /// - Tasks::Task Fetch(Invoices::InvoiceFetchParams @params); - - /// - /// This endpoint can be used to fetch the upcoming [invoice](/core-concepts#invoice) - /// for the current billing period given a subscription. - /// - Tasks::Task FetchUpcoming( - Invoices::InvoiceFetchUpcomingParams @params - ); - - /// - /// This endpoint allows an eligible invoice to be issued manually. This is only - /// possible with invoices where status is `draft`, `will_auto_issue` is false, - /// and an `eligible_to_issue_at` is a time in the past. Issuing an invoice could - /// possibly trigger side effects, some of which could be customer-visible (e.g. - /// sending emails, auto-collecting payment, syncing the invoice to external providers, etc). - /// - Tasks::Task Issue(Invoices::InvoiceIssueParams @params); - - /// - /// This endpoint allows an invoice's status to be set the `paid` status. This - /// can only be done to invoices that are in the `issued` status. - /// - Tasks::Task MarkPaid(Invoices::InvoiceMarkPaidParams @params); - - /// - /// This endpoint collects payment for an invoice using the customer's default - /// payment method. This action can only be taken on invoices with status "issued". - /// - Tasks::Task Pay(Invoices::InvoicePayParams @params); - - /// - /// This endpoint allows an invoice's status to be set the `void` status. This - /// can only be done to invoices that are in the `issued` status. - /// - /// If the associated invoice has used the customer balance to change the amount - /// due, the customer balance operation will be reverted. For example, if the invoice - /// used \$10 of customer balance, that amount will be added back to the customer - /// balance upon voiding. - /// - /// If the invoice was used to purchase a credit block, but the invoice is not - /// yet paid, the credit block will be voided. If the invoice was created due to - /// a top-up, the top-up will be disabled. - /// - Tasks::Task Void(Invoices::InvoiceVoidParams @params); -} diff --git a/src/Orb/Service/Invoices/InvoiceService.cs b/src/Orb/Service/Invoices/InvoiceService.cs deleted file mode 100644 index b8a33c3a..00000000 --- a/src/Orb/Service/Invoices/InvoiceService.cs +++ /dev/null @@ -1,197 +0,0 @@ -using Http = System.Net.Http; -using Invoices = Orb.Models.Invoices; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Invoices; - -public sealed class InvoiceService : IInvoiceService -{ - readonly Orb::IOrbClient _client; - - public InvoiceService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create(Invoices::InvoiceCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Invoices::InvoiceUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - Invoices::InvoiceListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(Invoices::InvoiceFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchUpcoming( - Invoices::InvoiceFetchUpcomingParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Issue(Invoices::InvoiceIssueParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task MarkPaid(Invoices::InvoiceMarkPaidParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Pay(Invoices::InvoicePayParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Void(Invoices::InvoiceVoidParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Items/IItemService.cs b/src/Orb/Service/Items/IItemService.cs deleted file mode 100644 index e4494795..00000000 --- a/src/Orb/Service/Items/IItemService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Items = Orb.Models.Items; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Items; - -public interface IItemService -{ - /// - /// This endpoint is used to create an [Item](/core-concepts#item). - /// - Tasks::Task Create(Items::ItemCreateParams @params); - - /// - /// This endpoint can be used to update properties on the Item. - /// - Tasks::Task Update(Items::ItemUpdateParams @params); - - /// - /// This endpoint returns a list of all Items, ordered in descending order by creation time. - /// - Tasks::Task List(Items::ItemListParams @params); - - /// - /// Archive item - /// - Tasks::Task Archive(Items::ItemArchiveParams @params); - - /// - /// This endpoint returns an item identified by its item_id. - /// - Tasks::Task Fetch(Items::ItemFetchParams @params); -} diff --git a/src/Orb/Service/Items/ItemService.cs b/src/Orb/Service/Items/ItemService.cs deleted file mode 100644 index a22c406b..00000000 --- a/src/Orb/Service/Items/ItemService.cs +++ /dev/null @@ -1,114 +0,0 @@ -using Http = System.Net.Http; -using Items = Orb.Models.Items; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Items; - -public sealed class ItemService : IItemService -{ - readonly Orb::IOrbClient _client; - - public ItemService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create(Items::ItemCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Items::ItemUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List(Items::ItemListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Archive(Items::ItemArchiveParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(Items::ItemFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Metrics/IMetricService.cs b/src/Orb/Service/Metrics/IMetricService.cs deleted file mode 100644 index bdcbecf7..00000000 --- a/src/Orb/Service/Metrics/IMetricService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Metrics = Orb.Models.Metrics; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Metrics; - -public interface IMetricService -{ - /// - /// This endpoint is used to create a [metric](/core-concepts###metric) using a - /// SQL string. See [SQL support](/extensibility/advanced-metrics#sql-support) - /// for a description of constructing SQL queries with examples. - /// - Tasks::Task Create(Metrics::MetricCreateParams @params); - - /// - /// This endpoint allows you to update the `metadata` property on a metric. If - /// you pass `null` for the metadata value, it will clear any existing metadata - /// for that invoice. - /// - Tasks::Task Update(Metrics::MetricUpdateParams @params); - - /// - /// This endpoint is used to fetch [metric](/core-concepts##metric) details given - /// a metric identifier. It returns information about the metrics including its - /// name, description, and item. - /// - Tasks::Task List(Metrics::MetricListParams @params); - - /// - /// This endpoint is used to list [metrics](/core-concepts#metric). It returns - /// information about the metrics including its name, description, and item. - /// - Tasks::Task Fetch(Metrics::MetricFetchParams @params); -} diff --git a/src/Orb/Service/Metrics/MetricService.cs b/src/Orb/Service/Metrics/MetricService.cs deleted file mode 100644 index dcb3404e..00000000 --- a/src/Orb/Service/Metrics/MetricService.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Metrics = Orb.Models.Metrics; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Metrics; - -public sealed class MetricService : IMetricService -{ - readonly Orb::IOrbClient _client; - - public MetricService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create(Metrics::MetricCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Metrics::MetricUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - Metrics::MetricListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(Metrics::MetricFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Plans/ExternalPlanID/ExternalPlanIDService.cs b/src/Orb/Service/Plans/ExternalPlanID/ExternalPlanIDService.cs deleted file mode 100644 index 721929fa..00000000 --- a/src/Orb/Service/Plans/ExternalPlanID/ExternalPlanIDService.cs +++ /dev/null @@ -1,58 +0,0 @@ -using ExternalPlanID = Orb.Models.Plans.ExternalPlanID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using Plans = Orb.Models.Plans; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Plans.ExternalPlanID; - -public sealed class ExternalPlanIDService : IExternalPlanIDService -{ - readonly Orb::IOrbClient _client; - - public ExternalPlanIDService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Update(ExternalPlanID::ExternalPlanIDUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(ExternalPlanID::ExternalPlanIDFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Plans/ExternalPlanID/IExternalPlanIDService.cs b/src/Orb/Service/Plans/ExternalPlanID/IExternalPlanIDService.cs deleted file mode 100644 index 84811bba..00000000 --- a/src/Orb/Service/Plans/ExternalPlanID/IExternalPlanIDService.cs +++ /dev/null @@ -1,34 +0,0 @@ -using ExternalPlanID = Orb.Models.Plans.ExternalPlanID; -using Plans = Orb.Models.Plans; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Plans.ExternalPlanID; - -public interface IExternalPlanIDService -{ - /// - /// This endpoint can be used to update the `external_plan_id`, and `metadata` - /// of an existing plan. - /// - /// Other fields on a plan are currently immutable. - /// - Tasks::Task Update(ExternalPlanID::ExternalPlanIDUpdateParams @params); - - /// - /// This endpoint is used to fetch [plan](/core-concepts##plan-and-price) details - /// given an external_plan_id identifier. It returns information about the prices - /// included in the plan and their configuration, as well as the product that the - /// plan is attached to. - /// - /// If multiple plans are found to contain the specified external_plan_id, the - /// active plans will take priority over archived ones, and among those, the endpoint - /// will return the most recently created plan. - /// - /// ## Serialized prices Orb supports a few different pricing models out of the - /// box. Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) - /// object. The `model_type` field determines the key for the configuration object - /// that is present. A detailed explanation of price types can be found in the [Price - /// schema](/core-concepts#plan-and-price). " - /// - Tasks::Task Fetch(ExternalPlanID::ExternalPlanIDFetchParams @params); -} diff --git a/src/Orb/Service/Plans/IPlanService.cs b/src/Orb/Service/Plans/IPlanService.cs deleted file mode 100644 index 85824dc7..00000000 --- a/src/Orb/Service/Plans/IPlanService.cs +++ /dev/null @@ -1,46 +0,0 @@ -using ExternalPlanID = Orb.Service.Plans.ExternalPlanID; -using Plans = Orb.Models.Plans; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Plans; - -public interface IPlanService -{ - ExternalPlanID::IExternalPlanIDService ExternalPlanID { get; } - - /// - /// This endpoint allows creation of plans including their prices. - /// - Tasks::Task Create(Plans::PlanCreateParams @params); - - /// - /// This endpoint can be used to update the `external_plan_id`, and `metadata` - /// of an existing plan. - /// - /// Other fields on a plan are currently immutable. - /// - Tasks::Task Update(Plans::PlanUpdateParams @params); - - /// - /// This endpoint returns a list of all [plans](/core-concepts#plan-and-price) for - /// an account in a list format. The list of plans is ordered starting from the - /// most recently created plan. The response also includes [`pagination_metadata`](/api-reference/pagination), - /// which lets the caller retrieve the next page of results if they exist. - /// - Tasks::Task List(Plans::PlanListParams @params); - - /// - /// This endpoint is used to fetch [plan](/core-concepts#plan-and-price) details - /// given a plan identifier. It returns information about the prices included in - /// the plan and their configuration, as well as the product that the plan is attached to. - /// - /// ## Serialized prices Orb supports a few different pricing models out of the - /// box. Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) - /// object. The `model_type` field determines the key for the configuration object - /// that is present. A detailed explanation of price types can be found in the [Price schema](/core-concepts#plan-and-price). - /// - /// ## Phases Orb supports plan phases, also known as contract ramps. For plans - /// with phases, the serialized prices refer to all prices across all phases. - /// - Tasks::Task Fetch(Plans::PlanFetchParams @params); -} diff --git a/src/Orb/Service/Plans/PlanService.cs b/src/Orb/Service/Plans/PlanService.cs deleted file mode 100644 index d56a4fd6..00000000 --- a/src/Orb/Service/Plans/PlanService.cs +++ /dev/null @@ -1,104 +0,0 @@ -using ExternalPlanID = Orb.Service.Plans.ExternalPlanID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using Plans = Orb.Models.Plans; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Plans; - -public sealed class PlanService : IPlanService -{ - readonly Orb::IOrbClient _client; - - public PlanService(Orb::IOrbClient client) - { - _client = client; - _externalPlanID = new(() => new ExternalPlanID::ExternalPlanIDService(client)); - } - - readonly System::Lazy _externalPlanID; - public ExternalPlanID::IExternalPlanIDService ExternalPlanID - { - get { return _externalPlanID.Value; } - } - - public async Tasks::Task Create(Plans::PlanCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Plans::PlanUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List(Plans::PlanListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(Plans::PlanFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Prices/ExternalPriceID/ExternalPriceIDService.cs b/src/Orb/Service/Prices/ExternalPriceID/ExternalPriceIDService.cs deleted file mode 100644 index 1fb3a817..00000000 --- a/src/Orb/Service/Prices/ExternalPriceID/ExternalPriceIDService.cs +++ /dev/null @@ -1,62 +0,0 @@ -using ExternalPriceID = Orb.Models.Prices.ExternalPriceID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Prices.ExternalPriceID; - -public sealed class ExternalPriceIDService : IExternalPriceIDService -{ - readonly Orb::IOrbClient _client; - - public ExternalPriceIDService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Update( - ExternalPriceID::ExternalPriceIDUpdateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch( - ExternalPriceID::ExternalPriceIDFetchParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Prices/ExternalPriceID/IExternalPriceIDService.cs b/src/Orb/Service/Prices/ExternalPriceID/IExternalPriceIDService.cs deleted file mode 100644 index 9b684a2c..00000000 --- a/src/Orb/Service/Prices/ExternalPriceID/IExternalPriceIDService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ExternalPriceID = Orb.Models.Prices.ExternalPriceID; -using Models = Orb.Models; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Prices.ExternalPriceID; - -public interface IExternalPriceIDService -{ - /// - /// This endpoint allows you to update the `metadata` property on a price. If you - /// pass null for the metadata value, it will clear any existing metadata for that price. - /// - Tasks::Task Update(ExternalPriceID::ExternalPriceIDUpdateParams @params); - - /// - /// This endpoint returns a price given an external price id. See the [price creation - /// API](/api-reference/price/create-price) for more information about external - /// price aliases. - /// - Tasks::Task Fetch(ExternalPriceID::ExternalPriceIDFetchParams @params); -} diff --git a/src/Orb/Service/Prices/IPriceService.cs b/src/Orb/Service/Prices/IPriceService.cs deleted file mode 100644 index 197174f6..00000000 --- a/src/Orb/Service/Prices/IPriceService.cs +++ /dev/null @@ -1,122 +0,0 @@ -using ExternalPriceID = Orb.Service.Prices.ExternalPriceID; -using Models = Orb.Models; -using Prices = Orb.Models.Prices; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Prices; - -public interface IPriceService -{ - ExternalPriceID::IExternalPriceIDService ExternalPriceID { get; } - - /// - /// This endpoint is used to create a [price](/product-catalog/price-configuration). - /// A price created using this endpoint is always an add-on, meaning that it's - /// not associated with a specific plan and can instead be individually added to - /// subscriptions, including subscriptions on different plans. - /// - /// An `external_price_id` can be optionally specified as an alias to allow ergonomic - /// interaction with prices in the Orb API. - /// - /// See the [Price resource](/product-catalog/price-configuration) for the specification - /// of different price model configurations possible in this endpoint. - /// - Tasks::Task Create(Prices::PriceCreateParams @params); - - /// - /// This endpoint allows you to update the `metadata` property on a price. If you - /// pass null for the metadata value, it will clear any existing metadata for that price. - /// - Tasks::Task Update(Prices::PriceUpdateParams @params); - - /// - /// This endpoint is used to list all add-on prices created using the [price creation endpoint](/api-reference/price/create-price). - /// - Tasks::Task List(Prices::PriceListParams @params); - - /// - /// [NOTE] It is recommended to use the `/v1/prices/evaluate` which offers further - /// functionality, such as multiple prices, inline price definitions, and querying - /// over preview events. - /// - /// This endpoint is used to evaluate the output of a price for a given customer - /// and time range. It enables filtering and grouping the output using [computed - /// properties](/extensibility/advanced-metrics#computed-properties), supporting - /// the following workflows: - /// - /// 1. Showing detailed usage and costs to the end customer. 2. Auditing subtotals - /// on invoice line items. - /// - /// For these workflows, the expressiveness of computed properties in both the - /// filters and grouping is critical. For example, if you'd like to show your customer - /// their usage grouped by hour and another property, you can do so with the following - /// `grouping_keys`: `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. - /// If you'd like to examine a customer's usage for a specific property value, you - /// can do so with the following `filter`: `my_property = 'foo' AND my_other_property - /// = 'bar'`. - /// - /// By default, the start of the time range must be no more than 100 days ago and - /// the length of the results must be no greater than 1000. Note that this is a - /// POST endpoint rather than a GET endpoint because it employs a JSON body rather - /// than query parameters. - /// - Tasks::Task Evaluate(Prices::PriceEvaluateParams @params); - - /// - /// This endpoint is used to evaluate the output of price(s) for a given customer - /// and time range over ingested events. It enables filtering and grouping the output - /// using [computed properties](/extensibility/advanced-metrics#computed-properties), - /// supporting the following workflows: - /// - /// 1. Showing detailed usage and costs to the end customer. 2. Auditing subtotals - /// on invoice line items. - /// - /// For these workflows, the expressiveness of computed properties in both the - /// filters and grouping is critical. For example, if you'd like to show your customer - /// their usage grouped by hour and another property, you can do so with the following - /// `grouping_keys`: `["hour_floor_timestamp_millis(timestamp_millis)", "my_property"]`. - /// If you'd like to examine a customer's usage for a specific property value, you - /// can do so with the following `filter`: `my_property = 'foo' AND my_other_property - /// = 'bar'`. - /// - /// Prices may either reference existing prices in your Orb account or be defined - /// inline in the request body. Up to 100 prices can be evaluated in a single request. - /// - /// Prices are evaluated on ingested events and the start of the time range must - /// be no more than 100 days ago. To evaluate based off a set of provided events, - /// the [evaluate preview events](/api-reference/price/evaluate-preview-events) - /// endpoint can be used instead. - /// - /// Note that this is a POST endpoint rather than a GET endpoint because it employs - /// a JSON body rather than query parameters. - /// - Tasks::Task EvaluateMultiple( - Prices::PriceEvaluateMultipleParams @params - ); - - /// - /// This endpoint evaluates prices on preview events instead of actual usage, making - /// it ideal for building price calculators and cost estimation tools. You can filter - /// and group results using [computed properties](/extensibility/advanced-metrics#computed-properties) - /// to analyze pricing across different dimensions. - /// - /// Prices may either reference existing prices in your Orb account or be defined - /// inline in the request body. The endpoint has the following limitations: 1. - /// Up to 100 prices can be evaluated in a single request. 2. Up to 500 preview - /// events can be provided in a single request. - /// - /// A top-level customer_id is required to evaluate the preview events. Additionally, - /// all events without a customer_id will have the top-level customer_id added. - /// - /// Note that this is a POST endpoint rather than a GET endpoint because it employs - /// a JSON body rather than query parameters. - /// - Tasks::Task EvaluatePreviewEvents( - Prices::PriceEvaluatePreviewEventsParams @params - ); - - /// - /// This endpoint returns a price given an identifier. - /// - Tasks::Task Fetch(Prices::PriceFetchParams @params); -} diff --git a/src/Orb/Service/Prices/PriceService.cs b/src/Orb/Service/Prices/PriceService.cs deleted file mode 100644 index a8905581..00000000 --- a/src/Orb/Service/Prices/PriceService.cs +++ /dev/null @@ -1,174 +0,0 @@ -using ExternalPriceID = Orb.Service.Prices.ExternalPriceID; -using Http = System.Net.Http; -using Json = System.Text.Json; -using Models = Orb.Models; -using Orb = Orb; -using Prices = Orb.Models.Prices; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Prices; - -public sealed class PriceService : IPriceService -{ - readonly Orb::IOrbClient _client; - - public PriceService(Orb::IOrbClient client) - { - _client = client; - _externalPriceID = new(() => new ExternalPriceID::ExternalPriceIDService(client)); - } - - readonly System::Lazy _externalPriceID; - public ExternalPriceID::IExternalPriceIDService ExternalPriceID - { - get { return _externalPriceID.Value; } - } - - public async Tasks::Task Create(Prices::PriceCreateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update(Prices::PriceUpdateParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List(Prices::PriceListParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Evaluate( - Prices::PriceEvaluateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task EvaluateMultiple( - Prices::PriceEvaluateMultipleParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task EvaluatePreviewEvents( - Prices::PriceEvaluatePreviewEventsParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch(Prices::PriceFetchParams @params) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/SubscriptionChanges/ISubscriptionChangeService.cs b/src/Orb/Service/SubscriptionChanges/ISubscriptionChangeService.cs deleted file mode 100644 index 4aa31d0c..00000000 --- a/src/Orb/Service/SubscriptionChanges/ISubscriptionChangeService.cs +++ /dev/null @@ -1,38 +0,0 @@ -using SubscriptionChanges = Orb.Models.SubscriptionChanges; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.SubscriptionChanges; - -public interface ISubscriptionChangeService -{ - /// - /// This endpoint returns a subscription change given an identifier. - /// - /// A subscription change is created by including `Create-Pending-Subscription-Change: - /// True` in the header of a subscription mutation API call (e.g. [create subscription - /// endpoint](/api-reference/subscription/create-subscription), [schedule plan change - /// endpoint](/api-reference/subscription/schedule-plan-change), ...). The subscription - /// change will be referenced by the `pending_subscription_change` field in the response. - /// - Tasks::Task Retrieve( - SubscriptionChanges::SubscriptionChangeRetrieveParams @params - ); - - /// - /// Apply a subscription change to perform the intended action. If a positive amount - /// is passed with a request to this endpoint, any eligible invoices that were created - /// will be issued immediately if they only contain in-advance fees. - /// - Tasks::Task Apply( - SubscriptionChanges::SubscriptionChangeApplyParams @params - ); - - /// - /// Cancel a subscription change. The change can no longer be applied. A subscription - /// can only have one "pending" change at a time - use this endpoint to cancel an - /// existing change before creating a new one. - /// - Tasks::Task Cancel( - SubscriptionChanges::SubscriptionChangeCancelParams @params - ); -} diff --git a/src/Orb/Service/SubscriptionChanges/SubscriptionChangeService.cs b/src/Orb/Service/SubscriptionChanges/SubscriptionChangeService.cs deleted file mode 100644 index 0cbfee12..00000000 --- a/src/Orb/Service/SubscriptionChanges/SubscriptionChangeService.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionChanges = Orb.Models.SubscriptionChanges; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.SubscriptionChanges; - -public sealed class SubscriptionChangeService : ISubscriptionChangeService -{ - readonly Orb::IOrbClient _client; - - public SubscriptionChangeService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Retrieve( - SubscriptionChanges::SubscriptionChangeRetrieveParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Apply( - SubscriptionChanges::SubscriptionChangeApplyParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Cancel( - SubscriptionChanges::SubscriptionChangeCancelParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/Subscriptions/ISubscriptionService.cs b/src/Orb/Service/Subscriptions/ISubscriptionService.cs deleted file mode 100644 index c31cabf2..00000000 --- a/src/Orb/Service/Subscriptions/ISubscriptionService.cs +++ /dev/null @@ -1,764 +0,0 @@ -using SubscriptionChanges = Orb.Models.SubscriptionChanges; -using Subscriptions = Orb.Models.Subscriptions; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Subscriptions; - -public interface ISubscriptionService -{ - /// - /// A subscription represents the purchase of a plan by a customer. The customer - /// is identified by either the `customer_id` or the `external_customer_id`, and - /// exactly one of these fields must be provided. - /// - /// By default, subscriptions begin on the day that they're created and renew automatically - /// for each billing cycle at the cadence that's configured in the plan definition. - /// - /// The default configuration for subscriptions in Orb is **In-advance billing** - /// and **Beginning of month alignment** (see [Subscription](/core-concepts##subscription) - /// for more details). - /// - /// In order to change the alignment behavior, Orb also supports billing subscriptions - /// on the day of the month they are created. If `align_billing_with_subscription_start_date - /// = true` is specified, subscriptions have billing cycles that are aligned with - /// their `start_date`. For example, a subscription that begins on January 15th - /// will have a billing cycle from January 15th to February 15th. Every subsequent - /// billing cycle will continue to start and invoice on the 15th. - /// - /// If the "day" value is greater than the number of days in the month, the next - /// billing cycle will start at the end of the month. For example, if the start_date - /// is January 31st, the next billing cycle will start on February 28th. - /// - /// If a customer was created with a currency, Orb only allows subscribing the - /// customer to a plan with a matching `invoicing_currency`. If the customer does - /// not have a currency set, on subscription creation, we set the customer's currency - /// to be the `invoicing_currency` of the plan. - /// - /// ## Customize your customer's subscriptions - /// - /// Prices and adjustments in a plan can be added, removed, or replaced for the - /// subscription being created. This is useful when a customer has prices that differ - /// from the default prices for a specific plan. - /// - /// This feature is only available for accounts that have migrated to Subscription - /// Overrides Version 2. You can find your Subscription Overrides Version at the - /// bottom of your [Plans page](https://app.withorb.com/plans) - /// - /// ### Adding Prices - /// - /// To add prices, provide a list of objects with the key `add_prices`. An object - /// in the list must specify an existing add-on price with a `price_id` or `external_price_id` - /// field, or create a new add-on price by including an object with the key `price`, - /// identical to what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). - /// See the [Price resource](/product-catalog/price-configuration) for the specification - /// of different price model configurations possible in this object. - /// - /// If the plan has phases, each object in the list must include a number with - /// `plan_phase_order` key to indicate which phase the price should be added to. - /// - /// An object in the list can specify an optional `start_date` and optional `end_date`. - /// This is equivalent to creating a price interval with the [add/edit price intervals - /// endpoint](/api-reference/price-interval/add-or-edit-price-intervals). If unspecified, - /// the start or end date of the phase or subscription will be used. - /// - /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, - /// or `discounts`. This will create adjustments which apply only to this price. - /// - /// Additionally, an object in the list can specify an optional `reference_id`. - /// This ID can be used to reference this price when [adding an adjustment](#adding-adjustments) - /// in the same API call. However the ID is _transient_ and cannot be used to refer - /// to the price in future API calls. - /// - /// ### Removing Prices - /// - /// To remove prices, provide a list of objects with the key `remove_prices`. An - /// object in the list must specify a plan price with either a `price_id` or `external_price_id` field. - /// - /// ### Replacing Prices - /// - /// To replace prices, provide a list of objects with the key `replace_prices`. - /// An object in the list must specify a plan price to replace with the `replaces_price_id` - /// key, and it must specify a price to replace it with by either referencing an - /// existing add-on price with a `price_id` or `external_price_id` field, or by - /// creating a new add-on price by including an object with the key `price`, identical - /// to what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). - /// See the [Price resource](/product-catalog/price-configuration) for the specification - /// of different price model configurations possible in this object. - /// - /// For fixed fees, an object in the list can supply a `fixed_price_quantity` instead - /// of a `price`, `price_id`, or `external_price_id` field. This will update only - /// the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. - /// - /// The replacement price will have the same phase, if applicable, and the same - /// start and end dates as the price it replaces. - /// - /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, - /// or `discounts`. This will create adjustments which apply only to this price. - /// - /// Additionally, an object in the list can specify an optional `reference_id`. - /// This ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) - /// in the same API call. However the ID is _transient_ and cannot be used to refer - /// to the price in future API calls. - /// - /// ### Adding adjustments - /// - /// To add adjustments, provide a list of objects with the key `add_adjustments`. - /// An object in the list must include an object with the key `adjustment`, identical - /// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). - /// - /// If the plan has phases, each object in the list must include a number with - /// `plan_phase_order` key to indicate which phase the adjustment should be added to. - /// - /// An object in the list can specify an optional `start_date` and optional `end_date`. - /// If unspecified, the start or end date of the phase or subscription will be used. - /// - /// ### Removing adjustments - /// - /// To remove adjustments, provide a list of objects with the key `remove_adjustments`. - /// An object in the list must include a key, `adjustment_id`, with the ID of the - /// adjustment to be removed. - /// - /// ### Replacing adjustments - /// - /// To replace adjustments, provide a list of objects with the key `replace_adjustments`. - /// An object in the list must specify a plan adjustment to replace with the `replaces_adjustment_id` - /// key, and it must specify an adjustment to replace it with by including an object - /// with the key `adjustment`, identical to the adjustment object in the [add/edit - /// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). - /// - /// The replacement adjustment will have the same phase, if applicable, and the - /// same start and end dates as the adjustment it replaces. - /// - /// ## Price overrides (DEPRECATED) - /// - /// Price overrides are being phased out in favor adding/removing/replacing - /// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/create-subscription)) - /// - /// Price overrides are used to update some or all prices in a plan for the specific - /// subscription being created. This is useful when a new customer has negotiated - /// a rate that is unique to the customer. - /// - /// To override prices, provide a list of objects with the key `price_overrides`. - /// The price object in the list of overrides is expected to contain the existing - /// price id, the `model_type` and configuration. (See the [Price resource](/product-catalog/price-configuration) - /// for the specification of different price model configurations.) The numerical - /// values can be updated, but the billable metric, cadence, type, and name of - /// a price can not be overridden. - /// - /// ### Maximums and Minimums Minimums and maximums, much like price overrides, - /// can be useful when a new customer has negotiated a new or different minimum - /// or maximum spend cap than the default for a given price. If one exists for a - /// price and null is provided for the minimum/maximum override on creation, then - /// there will be no minimum/maximum on the new subscription. If no value is provided, - /// then the default price maximum or minimum is used. - /// - /// To add a minimum for a specific price, add `minimum_amount` to the specific - /// price in the `price_overrides` object. - /// - /// To add a maximum for a specific price, add `maximum_amount` to the specific - /// price in the `price_overrides` object. - /// - /// ### Minimum override example - /// - /// Price minimum override example: - /// - /// ```json { ... "id": "price_id", "model_type": "unit", "unit_config": - /// { "unit_amount": "0.50" }, "minimum_amount": "100.00" ... } ``` - /// - /// Removing an existing minimum example ```json { ... "id": "price_id", "model_type": - /// "unit", "unit_config": { "unit_amount": "0.50" }, "minimum_amount": - /// null ... } ``` - /// - /// ### Discounts Discounts, like price overrides, can be useful when a new customer - /// has negotiated a new or different discount than the default for a price. If - /// a discount exists for a price and a null discount is provided on creation, - /// then there will be no discount on the new subscription. - /// - /// To add a discount for a specific price, add `discount` to the price in the - /// `price_overrides` object. Discount should be a dictionary of the format: ```ts - /// { "discount_type": "amount" | "percentage" | "usage", "amount_discount": - /// string, "percentage_discount": string, "usage_discount": string } ``` where - /// either `amount_discount`, `percentage_discount`, or `usage_discount` is provided. - /// - /// Price discount example ```json { ... "id": "price_id", "model_type": - /// "unit", "unit_config": { "unit_amount": "0.50" }, "discount": {"discount_type": - /// "amount", "amount_discount": "175"}, } ``` - /// - /// Removing an existing discount example ```json { "customer_id": "customer_id", - /// "plan_id": "plan_id", "discount": null, "price_overrides": [ ... ] - /// ... } ``` - /// - /// ## Threshold Billing - /// - /// Orb supports invoicing for a subscription when a preconfigured usage threshold - /// is hit. To enable threshold billing, pass in an `invoicing_threshold`, which - /// is specified in the subscription's invoicing currency, when creating a subscription. - /// E.g. pass in `10.00` to issue an invoice when usage amounts hit \$10.00 for - /// a subscription that invoices in USD. - /// - Tasks::Task Create( - Subscriptions::SubscriptionCreateParams @params - ); - - /// - /// This endpoint can be used to update the `metadata`, `net terms`, `auto_collection`, - /// `invoicing_threshold`, and `default_invoice_memo` properties on a subscription. - /// - Tasks::Task Update( - Subscriptions::SubscriptionUpdateParams @params - ); - - /// - /// This endpoint returns a list of all subscriptions for an account as a [paginated](/api-reference/pagination) - /// list, ordered starting from the most recently created subscription. For a full - /// discussion of the subscription resource, see [Subscription](/core-concepts##subscription). - /// - /// Subscriptions can be filtered for a specific customer by using either the customer_id - /// or external_customer_id query parameters. To filter subscriptions for multiple - /// customers, use the customer_id[] or external_customer_id[] query parameters. - /// - Tasks::Task List(Subscriptions::SubscriptionListParams @params); - - /// - /// This endpoint can be used to cancel an existing subscription. It returns the - /// serialized subscription object with an `end_date` parameter that signifies when - /// the subscription will transition to an ended state. - /// - /// The body parameter `cancel_option` determines the cancellation behavior. Orb - /// supports three cancellation options: - `end_of_subscription_term`: stops the - /// subscription from auto-renewing. Subscriptions that have been cancelled with - /// this option can still incur charges for the remainder of their term: - - /// Issuing this cancellation request for a monthly subscription will keep the subscription - /// active until the start of the subsequent month, and potentially issue - /// an invoice for any usage charges incurred in the intervening period. - /// - Issuing this cancellation request for a quarterly subscription will keep - /// the subscription active until the end of the quarter and potentially - /// issue an invoice for any usage charges incurred in the intervening period. - /// - Issuing this cancellation request for a yearly subscription will keep - /// the subscription active for the full year. For example, a yearly subscription - /// starting on 2021-11-01 and cancelled on 2021-12-08 will remain active - /// until 2022-11-01 and potentially issue charges in the intervening months for - /// any recurring monthly usage charges in its plan. - **Note**: If a - /// subscription's plan contains prices with difference cadences, the end of term - /// date will be determined by the largest cadence value. For example, cancelling - /// end of term for a subscription with a quarterly fixed fee with a monthly - /// usage fee will result in the subscription ending at the end of the quarter. - /// - /// - `immediate`: ends the subscription immediately, setting the `end_date` to - /// the current time: - Subscriptions that have been cancelled with this option - /// will be invoiced immediately. This invoice will include any usage fees - /// incurred in the billing period up to the cancellation, along with any prorated - /// recurring fees for the billing period, if applicable. - **Note**: - /// If the subscription has a recurring fee that was paid in-advance, the prorated - /// amount for the remaining time period will be added to the [customer's - /// balance](list-balance-transactions) upon immediate cancellation. However, - /// if the customer is ineligible to use the customer balance, the subscription - /// cannot be cancelled immediately. - /// - /// - `requested_date`: ends the subscription on a specified date, which requires - /// a `cancellation_date` to be passed in. If no timezone is provided, the customer's - /// timezone is used. For example, a subscription starting on January 1st with - /// a monthly price can be set to be cancelled on the first of any month after January - /// 1st (e.g. March 1st, April 1st, May 1st). A subscription with multiple prices - /// with different cadences defines the "term" to be the highest cadence of the prices. - /// - /// Upcoming subscriptions are only eligible for immediate cancellation, which - /// will set the `end_date` equal to the `start_date` upon cancellation. - /// - /// ## Backdated cancellations Orb allows you to cancel a subscription in the past - /// as long as there are no paid invoices between the `requested_date` and the current - /// time. If the cancellation is after the latest issued invoice, Orb will generate - /// a balance refund for the current period. If the cancellation is before the - /// most recently issued invoice, Orb will void the intervening invoice and generate - /// a new one based on the new dates for the subscription. See the section on [cancellation behaviors](/product-catalog/creating-subscriptions#cancellation-behaviors). - /// - Tasks::Task Cancel( - Subscriptions::SubscriptionCancelParams @params - ); - - /// - /// This endpoint is used to fetch a [Subscription](/core-concepts##subscription) - /// given an identifier. - /// - Tasks::Task Fetch(Subscriptions::SubscriptionFetchParams @params); - - /// - /// This endpoint is used to fetch a day-by-day snapshot of a subscription's costs - /// in Orb, calculated by applying pricing information to the underlying usage (see - /// the [subscription usage endpoint](fetch-subscription-usage) to fetch usage per - /// metric, in usage units rather than a currency). - /// - /// The semantics of this endpoint exactly mirror those of [fetching a customer's - /// costs](fetch-customer-costs). Use this endpoint to limit your analysis of costs - /// to a specific subscription for the customer (e.g. to de-aggregate costs when - /// a customer's subscription has started and stopped on the same day). - /// - Tasks::Task FetchCosts( - Subscriptions::SubscriptionFetchCostsParams @params - ); - - /// - /// This endpoint returns a [paginated](/api-reference/pagination) list of all plans - /// associated with a subscription along with their start and end dates. This list - /// contains the subscription's initial plan along with past and future plan changes. - /// - Tasks::Task FetchSchedule( - Subscriptions::SubscriptionFetchScheduleParams @params - ); - - /// - /// This endpoint is used to fetch a subscription's usage in Orb. Especially when - /// combined with optional query parameters, this endpoint is a powerful way to - /// build visualizations on top of Orb's event data and metrics. - /// - /// With no query parameters specified, this endpoint returns usage for the subscription's - /// _current billing period_ across each billable metric that participates in the - /// subscription. Usage quantities returned are the result of evaluating the metric - /// definition for the entirety of the customer's billing period. - /// - /// ### Default response shape Orb returns a `data` array with an object corresponding - /// to each billable metric. Nested within this object is a `usage` array which - /// has a `quantity` value and a corresponding `timeframe_start` and `timeframe_end`. - /// The `quantity` value represents the calculated usage value for the billable - /// metric over the specified timeframe (inclusive of the `timeframe_start` timestamp - /// and exclusive of the `timeframe_end` timestamp). - /// - /// Orb will include _every_ window in the response starting from the beginning - /// of the billing period, even when there were no events (and therefore no usage) - /// in the window. This increases the size of the response but prevents the caller - /// from filling in gaps and handling cumbersome time-based logic. - /// - /// The query parameters in this endpoint serve to override this behavior and provide - /// some key functionality, as listed below. Note that this functionality can also - /// be used _in conjunction_ with each other, e.g. to display grouped usage on a - /// custom timeframe. - /// - /// ## Custom timeframe In order to view usage for a custom timeframe rather than - /// the current billing period, specify a `timeframe_start` and `timeframe_end`. - /// This will calculate quantities for usage incurred between timeframe_start (inclusive) - /// and timeframe_end (exclusive), i.e. `[timeframe_start, timeframe_end)`. - /// - /// Note: - These timestamps must be specified in ISO 8601 format and UTC timezone, - /// e.g. `2022-02-01T05:00:00Z`. - Both parameters must be specified if either is specified. - /// - /// ## Grouping by custom attributes In order to view a single metric grouped by - /// a specific _attribute_ that each event is tagged with (e.g. `cluster`), you - /// must additionally specify a `billable_metric_id` and a `group_by` key. The `group_by` - /// key denotes the event property on which to group. - /// - /// When returning grouped usage, only usage for `billable_metric_id` is returned, - /// and a separate object in the `data` array is returned for each value of the - /// `group_by` key present in your events. The `quantity` value is the result of - /// evaluating the billable metric for events filtered to a single value of the - /// `group_by` key. - /// - /// Orb expects that events that match the billable metric will contain values in - /// the `properties` dictionary that correspond to the `group_by` key specified. - /// By default, Orb will not return a `null` group (i.e. events that match the - /// metric but do not have the key set). Currently, it is only possible to view - /// usage grouped by a single attribute at a time. - /// - /// When viewing grouped usage, Orb uses pagination to limit the response size - /// to 1000 groups by default. If there are more groups for a given subscription, - /// pagination metadata in the response can be used to fetch all of the data. - /// - /// The following example shows usage for an "API Requests" billable metric grouped - /// by `region`. Note the extra `metric_group` dictionary in the response, which - /// provides metadata about the group: - /// - /// ```json { "data": [ { "usage": [ { - /// "quantity": 0.19291, "timeframe_start": - /// "2021-10-01T07:00:00Z", "timeframe_end": "2021-10-02T07:00:00Z", - /// }, ... ], "metric_group": - /// { "property_key": "region", "property_value": - /// "asia/pacific" }, "billable_metric": { - /// "id": "Fe9pbpMk86xpwdGB", "name": "API Requests" - /// }, "view_mode": "periodic" }, ... ] } ``` - /// - /// ## Windowed usage The `granularity` parameter can be used to _window_ the usage - /// `quantity` value into periods. When not specified, usage is returned for the - /// entirety of the time range. - /// - /// When `granularity = day` is specified with a timeframe longer than a day, Orb - /// will return a `quantity` value for each full day between `timeframe_start` - /// and `timeframe_end`. Note that the days are demarcated by the _customer's local midnight_. - /// - /// For example, with `timeframe_start = 2022-02-01T05:00:00Z`, `timeframe_end - /// = 2022-02-04T01:00:00Z` and `granularity=day`, the following windows will be - /// returned for a customer in the `America/Los_Angeles` timezone since local midnight - /// is `08:00` UTC: - `[2022-02-01T05:00:00Z, 2022-02-01T08:00:00Z)` - `[2022-02-01T08:00:00, - /// 2022-02-02T08:00:00Z)` - `[2022-02-02T08:00:00, 2022-02-03T08:00:00Z)` - `[2022-02-03T08:00:00, 2022-02-04T01:00:00Z)` - /// - /// ```json { "data": [ { "billable_metric": { - /// "id": "Q8w89wjTtBdejXKsm", "name": "API Requests" - /// }, "usage": [ { "quantity": - /// 0, "timeframe_end": "2022-02-01T08:00:00+00:00", - /// "timeframe_start": "2022-02-01T05:00:00+00:00" - /// }, { - /// - /// "quantity": 0, "timeframe_end": "2022-02-02T08:00:00+00:00", - /// "timeframe_start": "2022-02-01T08:00:00+00:00" - /// }, { "quantity": 0, - /// "timeframe_end": "2022-02-03T08:00:00+00:00", "timeframe_start": - /// "2022-02-02T08:00:00+00:00" }, { - /// "quantity": 0, "timeframe_end": "2022-02-04T01:00:00+00:00", - /// "timeframe_start": "2022-02-03T08:00:00+00:00" - /// } ], "view_mode": "periodic" }, - /// ... ] } ``` - /// - /// ## Decomposable vs. non-decomposable metrics Billable metrics fall into one - /// of two categories: decomposable and non-decomposable. A decomposable billable - /// metric, such as a sum or a count, can be displayed and aggregated across arbitrary - /// timescales. On the other hand, a non-decomposable metric is not meaningful - /// when only a slice of the billing window is considered. - /// - /// As an example, if we have a billable metric that's defined to count unique users, - /// displaying a graph of unique users for each day is not representative of the - /// billable metric value over the month (days could have an overlapping set of - /// 'unique' users). Instead, what's useful for any given day is the number of - /// unique users in the billing period so far, which are the _cumulative_ unique users. - /// - /// Accordingly, this endpoint returns treats these two types of metrics differently - /// when `group_by` is specified: - Decomposable metrics can be grouped by any - /// event property. - Non-decomposable metrics can only be grouped by the corresponding - /// price's invoice grouping key. If no invoice grouping key is present, the metric - /// does not support `group_by`. - /// - /// ## Matrix prices When a billable metric is attached to a price that uses matrix - /// pricing, it's important to view usage grouped by those matrix dimensions. In - /// this case, use the query parameters `first_dimension_key`, `first_dimension_value` - /// and `second_dimension_key`, `second_dimension_value` while filtering to a specific `billable_metric_id`. - /// - /// For example, if your compute metric has a separate unit price (i.e. a matrix - /// pricing model) per `region` and `provider`, your request might provide the - /// following parameters: - /// - /// - `first_dimension_key`: `region` - `first_dimension_value`: `us-east-1` - - /// `second_dimension_key`: `provider` - `second_dimension_value`: `aws` - /// - Tasks::Task FetchUsage( - Subscriptions::SubscriptionFetchUsageParams @params - ); - - /// - /// This endpoint is used to add and edit subscription [price intervals](/api-reference/price-interval/add-or-edit-price-intervals). - /// By making modifications to a subscription’s price intervals, you can [flexibly - /// and atomically control the billing behavior of a subscription](/product-catalog/modifying-subscriptions). - /// - /// ## Adding price intervals - /// - /// Prices can be added as price intervals to a subscription by specifying them - /// in the `add` array. A `price_id` or `external_price_id` from an add-on price - /// or previously removed plan price can be specified to reuse an existing price - /// definition (however, please note that prices from other plans cannot be added - /// to the subscription). Additionally, a new price can be specified using the `price` - /// field — this price will be created automatically. - /// - /// A `start_date` must be specified for the price interval. This is the date when - /// the price will start billing on the subscription, so this will notably result - /// in an immediate charge at this time for any billed in advance fixed fees. The - /// `end_date` will default to null, resulting in a price interval that will bill - /// on a continually recurring basis. Both of these dates can be set in the past - /// or the future and Orb will generate or modify invoices to ensure the subscription’s - /// invoicing behavior is correct. - /// - /// Additionally, a discount, minimum, or maximum can be specified on the price - /// interval. This will only apply to this price interval, not any other price - /// intervals on the subscription. - /// - /// ## Adjustment intervals - /// - /// An adjustment interval represents the time period that a particular adjustment - /// (a discount, minimum, or maximum) applies to the prices on a subscription. - /// Adjustment intervals can be added to a subscription by specifying them in the - /// `add_adjustments` array, or modified via the `edit_adjustments` array. When - /// creating an adjustment interval, you'll need to provide the definition of the - /// new adjustment (the type of adjustment, and which prices it applies to), as - /// well as the start and end dates for the adjustment interval. The start and end - /// dates of an existing adjustment interval can be edited via the `edit_adjustments` - /// field (just like price intervals). (To "change" the amount of a discount, minimum, - /// or maximum, then, you'll need to end the existing interval, and create a new - /// adjustment interval with the new amount and a start date that matches the end - /// date of the previous interval.) - /// - /// ## Editing price intervals - /// - /// Price intervals can be adjusted by specifying edits to make in the `edit` array. - /// A `price_interval_id` to edit must be specified — this can be retrieved from - /// the `price_intervals` field on the subscription. - /// - /// A new `start_date` or `end_date` can be specified to change the range of the - /// price interval, which will modify past or future invoices to ensure correctness. - /// If either of these dates are unspecified, they will default to the existing - /// date on the price interval. To remove a price interval entirely from a subscription, - /// set the `end_date` to be equivalent to the `start_date`. - /// - /// ## Fixed fee quantity transitions The fixed fee quantity transitions for a fixed - /// fee price interval can also be specified when adding or editing by passing an - /// array for `fixed_fee_quantity_transitions`. A fixed fee quantity transition - /// must have a `quantity` and an `effective_date`, which is the date after which - /// the new quantity will be used for billing. If a fixed fee quantity transition - /// is scheduled at a billing period boundary, the full quantity will be billed - /// on an invoice with the other prices on the subscription. If the fixed fee quantity - /// transition is scheduled mid-billing period, the difference between the existing - /// quantity and quantity specified in the transition will be prorated for the rest - /// of the billing period and billed immediately, which will generate a new invoice. - /// - /// Notably, the list of fixed fee quantity transitions passed will overwrite the - /// existing fixed fee quantity transitions on the price interval, so the entire - /// list of transitions must be specified to add additional transitions. The existing - /// list of transitions can be retrieved using the `fixed_fee_quantity_transitions` - /// property on a subscription’s serialized price intervals. - /// - Tasks::Task PriceIntervals( - Subscriptions::SubscriptionPriceIntervalsParams @params - ); - - /// - /// Redeem a coupon effective at a given time. - /// - Tasks::Task RedeemCoupon( - Subscriptions::SubscriptionRedeemCouponParams @params - ); - - /// - /// This endpoint can be used to change an existing subscription's plan. It returns - /// the serialized updated subscription object. - /// - /// The body parameter `change_option` determines when the plan change occurrs. - /// Orb supports three options: - `end_of_subscription_term`: changes the plan - /// at the end of the existing plan's term. - Issuing this plan change request - /// for a monthly subscription will keep the existing plan active until the start - /// of the subsequent month. Issuing this plan change request for a yearly - /// subscription will keep the existing plan active for the full year. Charges - /// incurred in the remaining period will be invoiced as normal. - Example: - /// The plan is billed monthly on the 1st of the month, the request is made on January - /// 15th, so the plan will be changed on February 1st, and invoice will be - /// issued on February 1st for the last month of the original plan. - `immediate`: - /// changes the plan immediately. - Subscriptions that have their plan changed - /// with this option will move to the new plan immediately, and be invoiced - /// immediately. - This invoice will include any usage fees incurred in the - /// billing period up to the change, along with any prorated recurring fees - /// for the billing period, if applicable. - Example: The plan is billed monthly - /// on the 1st of the month, the request is made on January 15th, so the plan will - /// be changed on January 15th, and an invoice will be issued for the partial - /// month, from January 1 to January 15, on the original plan. - `requested_date`: - /// changes the plan on the requested date (`change_date`). - If no timezone - /// is provided, the customer's timezone is used. The `change_date` body parameter - /// is required if this option is chosen. - Example: The plan is billed - /// monthly on the 1st of the month, the request is made on January 15th, with - /// a requested `change_date` of February 15th, so the plan will be changed - /// on February 15th, and invoices will be issued on February 1st and February 15th. - /// - /// Note that one of `plan_id` or `external_plan_id` is required in the request - /// body for this operation. - /// - /// ## Customize your customer's subscriptions - /// - /// Prices and adjustments in a plan can be added, removed, or replaced on the subscription - /// when you schedule the plan change. This is useful when a customer has prices - /// that differ from the default prices for a specific plan. - /// - /// This feature is only available for accounts that have migrated to Subscription - /// Overrides Version 2. You can find your Subscription Overrides Version at the - /// bottom of your [Plans page](https://app.withorb.com/plans) - /// - /// ### Adding Prices - /// - /// To add prices, provide a list of objects with the key `add_prices`. An object - /// in the list must specify an existing add-on price with a `price_id` or `external_price_id` - /// field, or create a new add-on price by including an object with the key `price`, - /// identical to what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). - /// See the [Price resource](/product-catalog/price-configuration) for the specification - /// of different price model configurations possible in this object. - /// - /// If the plan has phases, each object in the list must include a number with - /// `plan_phase_order` key to indicate which phase the price should be added to. - /// - /// An object in the list can specify an optional `start_date` and optional `end_date`. - /// If `start_date` is unspecified, the start of the phase / plan change time will - /// be used. If `end_date` is unspecified, it will finish at the end of the phase - /// / have no end time. - /// - /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, - /// or `discounts`. This will create adjustments which apply only to this price. - /// - /// Additionally, an object in the list can specify an optional `reference_id`. - /// This ID can be used to reference this price when [adding an adjustment](#adding-adjustments) - /// in the same API call. However the ID is _transient_ and cannot be used to refer - /// to the price in future API calls. - /// - /// ### Removing Prices - /// - /// To remove prices, provide a list of objects with the key `remove_prices`. An - /// object in the list must specify a plan price with either a `price_id` or `external_price_id` field. - /// - /// ### Replacing Prices - /// - /// To replace prices, provide a list of objects with the key `replace_prices`. - /// An object in the list must specify a plan price to replace with the `replaces_price_id` - /// key, and it must specify a price to replace it with by either referencing an - /// existing add-on price with a `price_id` or `external_price_id` field, or by - /// creating a new add-on price by including an object with the key `price`, identical - /// to what would be used in the request body for the [create price endpoint](/api-reference/price/create-price). - /// See the [Price resource](/product-catalog/price-configuration) for the specification - /// of different price model configurations possible in this object. - /// - /// For fixed fees, an object in the list can supply a `fixed_price_quantity` instead - /// of a `price`, `price_id`, or `external_price_id` field. This will update only - /// the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. - /// - /// The replacement price will have the same phase, if applicable, and the same - /// start and end dates as the price it replaces. - /// - /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, - /// or `discounts`. This will create adjustments which apply only to this price. - /// - /// Additionally, an object in the list can specify an optional `reference_id`. - /// This ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) - /// in the same API call. However the ID is _transient_ and cannot be used to refer - /// to the price in future API calls. - /// - /// ### Adding adjustments - /// - /// To add adjustments, provide a list of objects with the key `add_adjustments`. - /// An object in the list must include an object with the key `adjustment`, identical - /// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). - /// - /// If the plan has phases, each object in the list must include a number with - /// `plan_phase_order` key to indicate which phase the adjustment should be added to. - /// - /// An object in the list can specify an optional `start_date` and optional `end_date`. - /// If `start_date` is unspecified, the start of the phase / plan change time will - /// be used. If `end_date` is unspecified, it will finish at the end of the phase - /// / have no end time. - /// - /// ### Removing adjustments - /// - /// To remove adjustments, provide a list of objects with the key `remove_adjustments`. - /// An object in the list must include a key, `adjustment_id`, with the ID of the - /// adjustment to be removed. - /// - /// ### Replacing adjustments - /// - /// To replace adjustments, provide a list of objects with the key `replace_adjustments`. - /// An object in the list must specify a plan adjustment to replace with the `replaces_adjustment_id` - /// key, and it must specify an adjustment to replace it with by including an object - /// with the key `adjustment`, identical to the adjustment object in the [add/edit - /// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). - /// - /// The replacement adjustment will have the same phase, if applicable, and the - /// same start and end dates as the adjustment it replaces. - /// - /// ## Price overrides (DEPRECATED) - /// - /// Price overrides are being phased out in favor adding/removing/replacing - /// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/schedule-plan-change)) - /// - /// Price overrides are used to update some or all prices in a plan for the specific - /// subscription being created. This is useful when a new customer has negotiated - /// a rate that is unique to the customer. - /// - /// To override prices, provide a list of objects with the key `price_overrides`. - /// The price object in the list of overrides is expected to contain the existing - /// price id, the `model_type` and configuration. (See the [Price resource](/product-catalog/price-configuration) - /// for the specification of different price model configurations.) The numerical - /// values can be updated, but the billable metric, cadence, type, and name of - /// a price can not be overridden. - /// - /// ### Maximums, and minimums Price overrides are used to update some or all prices - /// in the target plan. Minimums and maximums, much like price overrides, can be - /// useful when a new customer has negotiated a new or different minimum or maximum - /// spend cap than the default for the plan. The request format for maximums and - /// minimums is the same as those in [subscription creation](create-subscription). - /// - /// ## Scheduling multiple plan changes When scheduling multiple plan changes with - /// the same date, the latest plan change on that day takes effect. - /// - /// ## Prorations for in-advance fees By default, Orb calculates the prorated difference - /// in any fixed fees when making a plan change, adjusting the customer balance - /// as needed. For details on this behavior, see [Modifying subscriptions](/product-catalog/modifying-subscriptions#prorations-for-in-advance-fees). - /// - Tasks::Task SchedulePlanChange( - Subscriptions::SubscriptionSchedulePlanChangeParams @params - ); - - /// - /// Manually trigger a phase, effective the given date (or the current time, if - /// not specified). - /// - Tasks::Task TriggerPhase( - Subscriptions::SubscriptionTriggerPhaseParams @params - ); - - /// - /// This endpoint can be used to unschedule any pending cancellations for a subscription. - /// - /// To be eligible, the subscription must currently be active and have a future - /// cancellation. This operation will turn on auto-renew, ensuring that the subscription - /// does not end at the currently scheduled cancellation time. - /// - Tasks::Task UnscheduleCancellation( - Subscriptions::SubscriptionUnscheduleCancellationParams @params - ); - - /// - /// This endpoint can be used to clear scheduled updates to the quantity for a fixed fee. - /// - /// If there are no updates scheduled, a request validation error will be returned - /// with a 400 status code. - /// - Tasks::Task UnscheduleFixedFeeQuantityUpdates( - Subscriptions::SubscriptionUnscheduleFixedFeeQuantityUpdatesParams @params - ); - - /// - /// This endpoint can be used to unschedule any pending plan changes on an existing - /// subscription. When called, all upcoming plan changes will be unscheduled. - /// - Tasks::Task UnschedulePendingPlanChanges( - Subscriptions::SubscriptionUnschedulePendingPlanChangesParams @params - ); - - /// - /// This endpoint can be used to update the quantity for a fixed fee. - /// - /// To be eligible, the subscription must currently be active and the price specified - /// must be a fixed fee (not usage-based). This operation will immediately update - /// the quantity for the fee, or if a `effective_date` is passed in, will update - /// the quantity on the requested date at midnight in the customer's timezone. - /// - /// In order to change the fixed fee quantity as of the next draft invoice for - /// this subscription, pass `change_option=upcoming_invoice` without an `effective_date` specified. - /// - /// If the fee is an in-advance fixed fee, it will also issue an immediate invoice - /// for the difference for the remainder of the billing period. - /// - Tasks::Task UpdateFixedFeeQuantity( - Subscriptions::SubscriptionUpdateFixedFeeQuantityParams @params - ); - - /// - /// This endpoint is used to update the trial end date for a subscription. The new - /// trial end date must be within the time range of the current plan (i.e. the new - /// trial end date must be on or after the subscription's start date on the current - /// plan, and on or before the subscription end date). - /// - /// In order to retroactively remove a trial completely, the end date can be set - /// to the transition date of the subscription to this plan (or, if this is the - /// first plan for this subscription, the subscription's start date). In order to - /// end a trial immediately, the keyword `immediate` can be provided as the trial - /// end date. - /// - /// By default, Orb will shift only the trial end date (and price intervals that - /// start or end on the previous trial end date), and leave all other future price - /// intervals untouched. If the `shift` parameter is set to `true`, Orb will shift - /// all subsequent price and adjustment intervals by the same amount as the trial - /// end date shift (so, e.g., if a plan change is scheduled or an add-on price was - /// added, that change will be pushed back by the same amount of time the trial - /// is extended). - /// - Tasks::Task UpdateTrial( - Subscriptions::SubscriptionUpdateTrialParams @params - ); -} diff --git a/src/Orb/Service/Subscriptions/SubscriptionService.cs b/src/Orb/Service/Subscriptions/SubscriptionService.cs deleted file mode 100644 index 8f2c6ae3..00000000 --- a/src/Orb/Service/Subscriptions/SubscriptionService.cs +++ /dev/null @@ -1,389 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using SubscriptionChanges = Orb.Models.SubscriptionChanges; -using Subscriptions = Orb.Models.Subscriptions; -using System = System; -using Tasks = System.Threading.Tasks; - -namespace Orb.Service.Subscriptions; - -public sealed class SubscriptionService : ISubscriptionService -{ - readonly Orb::IOrbClient _client; - - public SubscriptionService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Create( - Subscriptions::SubscriptionCreateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Update( - Subscriptions::SubscriptionUpdateParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Put, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task List( - Subscriptions::SubscriptionListParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Cancel( - Subscriptions::SubscriptionCancelParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task Fetch( - Subscriptions::SubscriptionFetchParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchCosts( - Subscriptions::SubscriptionFetchCostsParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchSchedule( - Subscriptions::SubscriptionFetchScheduleParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task FetchUsage( - Subscriptions::SubscriptionFetchUsageParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task PriceIntervals( - Subscriptions::SubscriptionPriceIntervalsParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task RedeemCoupon( - Subscriptions::SubscriptionRedeemCouponParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task SchedulePlanChange( - Subscriptions::SubscriptionSchedulePlanChangeParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task TriggerPhase( - Subscriptions::SubscriptionTriggerPhaseParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task UnscheduleCancellation( - Subscriptions::SubscriptionUnscheduleCancellationParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task UnscheduleFixedFeeQuantityUpdates( - Subscriptions::SubscriptionUnscheduleFixedFeeQuantityUpdatesParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task UnschedulePendingPlanChanges( - Subscriptions::SubscriptionUnschedulePendingPlanChangesParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task UpdateFixedFeeQuantity( - Subscriptions::SubscriptionUpdateFixedFeeQuantityParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } - - public async Tasks::Task UpdateTrial( - Subscriptions::SubscriptionUpdateTrialParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Post, @params.Url(this._client)) - { - Content = @params.BodyContent(), - }; - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Service/TopLevel/ITopLevelService.cs b/src/Orb/Service/TopLevel/ITopLevelService.cs deleted file mode 100644 index d175634c..00000000 --- a/src/Orb/Service/TopLevel/ITopLevelService.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Tasks = System.Threading.Tasks; -using TopLevel = Orb.Models.TopLevel; - -namespace Orb.Service.TopLevel; - -public interface ITopLevelService -{ - /// - /// This endpoint allows you to test your connection to the Orb API and check the - /// validity of your API key, passed in the Authorization header. This is particularly - /// useful for checking that your environment is set up properly, and is a great - /// choice for connectors and integrations. - /// - /// This API does not have any side-effects or return any Orb resources. - /// - Tasks::Task Ping(TopLevel::TopLevelPingParams @params); -} diff --git a/src/Orb/Service/TopLevel/TopLevelService.cs b/src/Orb/Service/TopLevel/TopLevelService.cs deleted file mode 100644 index f42cd9ec..00000000 --- a/src/Orb/Service/TopLevel/TopLevelService.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Http = System.Net.Http; -using Json = System.Text.Json; -using Orb = Orb; -using System = System; -using Tasks = System.Threading.Tasks; -using TopLevel = Orb.Models.TopLevel; - -namespace Orb.Service.TopLevel; - -public sealed class TopLevelService : ITopLevelService -{ - readonly Orb::IOrbClient _client; - - public TopLevelService(Orb::IOrbClient client) - { - _client = client; - } - - public async Tasks::Task Ping( - TopLevel::TopLevelPingParams @params - ) - { - Http::HttpRequestMessage webRequest = new(Http::HttpMethod.Get, @params.Url(this._client)); - @params.AddHeadersToRequest(webRequest, this._client); - using Http::HttpResponseMessage response = await _client.HttpClient.SendAsync(webRequest); - try - { - response.EnsureSuccessStatusCode(); - } - catch (Http::HttpRequestException e) - { - throw new Orb::HttpException(e.StatusCode, await response.Content.ReadAsStringAsync()); - } - return Json::JsonSerializer.Deserialize( - await response.Content.ReadAsStringAsync() - ) ?? throw new System::NullReferenceException(); - } -} diff --git a/src/Orb/Services/AlertService.cs b/src/Orb/Services/AlertService.cs new file mode 100644 index 00000000..e0b4e783 --- /dev/null +++ b/src/Orb/Services/AlertService.cs @@ -0,0 +1,353 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Alerts; + +namespace Orb.Services; + +/// +public sealed class AlertService : IAlertService +{ + /// + public IAlertService WithOptions(Func modifier) + { + return new AlertService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public AlertService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Retrieve( + AlertRetrieveParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.AlertID == null) + { + throw new OrbInvalidDataException("'parameters.AlertID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task Retrieve( + string alertID, + AlertRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Retrieve(parameters with { AlertID = alertID }, cancellationToken); + } + + /// + public async Task Update( + AlertUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.AlertConfigurationID == null) + { + throw new OrbInvalidDataException("'parameters.AlertConfigurationID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task Update( + string alertConfigurationID, + AlertUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.Update( + parameters with + { + AlertConfigurationID = alertConfigurationID, + }, + cancellationToken + ); + } + + /// + public async Task List( + AlertListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new AlertListPage(this, parameters, page); + } + + /// + public async Task CreateForCustomer( + AlertCreateForCustomerParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task CreateForCustomer( + string customerID, + AlertCreateForCustomerParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreateForCustomer( + parameters with + { + CustomerID = customerID, + }, + cancellationToken + ); + } + + /// + public async Task CreateForExternalCustomer( + AlertCreateForExternalCustomerParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task CreateForExternalCustomer( + string externalCustomerID, + AlertCreateForExternalCustomerParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreateForExternalCustomer( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } + + /// + public async Task CreateForSubscription( + AlertCreateForSubscriptionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task CreateForSubscription( + string subscriptionID, + AlertCreateForSubscriptionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreateForSubscription( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task Disable( + AlertDisableParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.AlertConfigurationID == null) + { + throw new OrbInvalidDataException("'parameters.AlertConfigurationID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task Disable( + string alertConfigurationID, + AlertDisableParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Disable( + parameters with + { + AlertConfigurationID = alertConfigurationID, + }, + cancellationToken + ); + } + + /// + public async Task Enable( + AlertEnableParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.AlertConfigurationID == null) + { + throw new OrbInvalidDataException("'parameters.AlertConfigurationID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var alert = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + alert.Validate(); + } + return alert; + } + + /// + public async Task Enable( + string alertConfigurationID, + AlertEnableParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Enable( + parameters with + { + AlertConfigurationID = alertConfigurationID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Beta/ExternalPlanIDService.cs b/src/Orb/Services/Beta/ExternalPlanIDService.cs new file mode 100644 index 00000000..ea487ead --- /dev/null +++ b/src/Orb/Services/Beta/ExternalPlanIDService.cs @@ -0,0 +1,161 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Beta; +using Orb.Models.Beta.ExternalPlanID; +using Orb.Models.Plans; + +namespace Orb.Services.Beta; + +/// +public sealed class ExternalPlanIDService : IExternalPlanIDService +{ + /// + public IExternalPlanIDService WithOptions(Func modifier) + { + return new ExternalPlanIDService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public ExternalPlanIDService(IOrbClient client) + { + _client = client; + } + + /// + public async Task CreatePlanVersion( + ExternalPlanIDCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalPlanID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalPlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var planVersion = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + planVersion.Validate(); + } + return planVersion; + } + + /// + public async Task CreatePlanVersion( + string externalPlanID, + ExternalPlanIDCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreatePlanVersion( + parameters with + { + ExternalPlanID = externalPlanID, + }, + cancellationToken + ); + } + + /// + public async Task FetchPlanVersion( + ExternalPlanIDFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.Version == null) + { + throw new OrbInvalidDataException("'parameters.Version' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var planVersion = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + planVersion.Validate(); + } + return planVersion; + } + + /// + public async Task FetchPlanVersion( + string version, + ExternalPlanIDFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.FetchPlanVersion( + parameters with + { + Version = version, + }, + cancellationToken + ); + } + + /// + public async Task SetDefaultPlanVersion( + ExternalPlanIDSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalPlanID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalPlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task SetDefaultPlanVersion( + string externalPlanID, + ExternalPlanIDSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.SetDefaultPlanVersion( + parameters with + { + ExternalPlanID = externalPlanID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Beta/IExternalPlanIDService.cs b/src/Orb/Services/Beta/IExternalPlanIDService.cs new file mode 100644 index 00000000..ed8434f0 --- /dev/null +++ b/src/Orb/Services/Beta/IExternalPlanIDService.cs @@ -0,0 +1,70 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Beta; +using Orb.Models.Beta.ExternalPlanID; +using Orb.Models.Plans; + +namespace Orb.Services.Beta; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IExternalPlanIDService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IExternalPlanIDService WithOptions(Func modifier); + + /// + /// This endpoint allows the creation of a new plan version for an existing plan. + /// + Task CreatePlanVersion( + ExternalPlanIDCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreatePlanVersion( + string externalPlanID, + ExternalPlanIDCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a plan version. It returns the phases, prices, + /// and adjustments present on this version of the plan. + /// + Task FetchPlanVersion( + ExternalPlanIDFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task FetchPlanVersion( + string version, + ExternalPlanIDFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows setting the default version of a plan. + /// + Task SetDefaultPlanVersion( + ExternalPlanIDSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task SetDefaultPlanVersion( + string externalPlanID, + ExternalPlanIDSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/BetaService.cs b/src/Orb/Services/BetaService.cs new file mode 100644 index 00000000..2fd923f5 --- /dev/null +++ b/src/Orb/Services/BetaService.cs @@ -0,0 +1,162 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Beta; +using Orb.Models.Plans; +using Orb.Services.Beta; + +namespace Orb.Services; + +/// +public sealed class BetaService : IBetaService +{ + /// + public IBetaService WithOptions(Func modifier) + { + return new BetaService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public BetaService(IOrbClient client) + { + _client = client; + _externalPlanID = new(() => new ExternalPlanIDService(client)); + } + + readonly Lazy _externalPlanID; + public IExternalPlanIDService ExternalPlanID + { + get { return _externalPlanID.Value; } + } + + /// + public async Task CreatePlanVersion( + BetaCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PlanID == null) + { + throw new OrbInvalidDataException("'parameters.PlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var planVersion = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + planVersion.Validate(); + } + return planVersion; + } + + /// + public async Task CreatePlanVersion( + string planID, + BetaCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreatePlanVersion(parameters with { PlanID = planID }, cancellationToken); + } + + /// + public async Task FetchPlanVersion( + BetaFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.Version == null) + { + throw new OrbInvalidDataException("'parameters.Version' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var planVersion = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + planVersion.Validate(); + } + return planVersion; + } + + /// + public async Task FetchPlanVersion( + string version, + BetaFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.FetchPlanVersion( + parameters with + { + Version = version, + }, + cancellationToken + ); + } + + /// + public async Task SetDefaultPlanVersion( + BetaSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PlanID == null) + { + throw new OrbInvalidDataException("'parameters.PlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task SetDefaultPlanVersion( + string planID, + BetaSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.SetDefaultPlanVersion( + parameters with + { + PlanID = planID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/CouponService.cs b/src/Orb/Services/CouponService.cs new file mode 100644 index 00000000..8ccfe13f --- /dev/null +++ b/src/Orb/Services/CouponService.cs @@ -0,0 +1,160 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Coupons; +using Coupons = Orb.Services.Coupons; + +namespace Orb.Services; + +/// +public sealed class CouponService : ICouponService +{ + /// + public ICouponService WithOptions(Func modifier) + { + return new CouponService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public CouponService(IOrbClient client) + { + _client = client; + _subscriptions = new(() => new Coupons::SubscriptionService(client)); + } + + readonly Lazy _subscriptions; + public Coupons::ISubscriptionService Subscriptions + { + get { return _subscriptions.Value; } + } + + /// + public async Task Create( + CouponCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var coupon = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + coupon.Validate(); + } + return coupon; + } + + /// + public async Task List( + CouponListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new CouponListPage(this, parameters, page); + } + + /// + public async Task Archive( + CouponArchiveParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CouponID == null) + { + throw new OrbInvalidDataException("'parameters.CouponID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var coupon = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + coupon.Validate(); + } + return coupon; + } + + /// + public async Task Archive( + string couponID, + CouponArchiveParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Archive(parameters with { CouponID = couponID }, cancellationToken); + } + + /// + public async Task Fetch( + CouponFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CouponID == null) + { + throw new OrbInvalidDataException("'parameters.CouponID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var coupon = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + coupon.Validate(); + } + return coupon; + } + + /// + public async Task Fetch( + string couponID, + CouponFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { CouponID = couponID }, cancellationToken); + } +} diff --git a/src/Orb/Services/Coupons/ISubscriptionService.cs b/src/Orb/Services/Coupons/ISubscriptionService.cs new file mode 100644 index 00000000..a5c40180 --- /dev/null +++ b/src/Orb/Services/Coupons/ISubscriptionService.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Coupons.Subscriptions; + +namespace Orb.Services.Coupons; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ISubscriptionService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + global::Orb.Services.Coupons.ISubscriptionService WithOptions( + Func modifier + ); + + /// + /// This endpoint returns a list of all subscriptions that have redeemed a given + /// coupon as a [paginated](/api-reference/pagination) list, ordered starting + /// from the most recently created subscription. For a full discussion of the + /// subscription resource, see [Subscription](/core-concepts#subscription). + /// + Task List( + SubscriptionListParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task List( + string couponID, + SubscriptionListParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Coupons/SubscriptionService.cs b/src/Orb/Services/Coupons/SubscriptionService.cs new file mode 100644 index 00000000..adebdddc --- /dev/null +++ b/src/Orb/Services/Coupons/SubscriptionService.cs @@ -0,0 +1,72 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Coupons.Subscriptions; +using Subscriptions = Orb.Models.Subscriptions; + +namespace Orb.Services.Coupons; + +/// +public sealed class SubscriptionService : global::Orb.Services.Coupons.ISubscriptionService +{ + /// + public global::Orb.Services.Coupons.ISubscriptionService WithOptions( + Func modifier + ) + { + return new global::Orb.Services.Coupons.SubscriptionService( + this._client.WithOptions(modifier) + ); + } + + readonly IOrbClient _client; + + public SubscriptionService(IOrbClient client) + { + _client = client; + } + + /// + public async Task List( + SubscriptionListParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CouponID == null) + { + throw new OrbInvalidDataException("'parameters.CouponID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new SubscriptionListPage(this, parameters, page); + } + + /// + public async Task List( + string couponID, + SubscriptionListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.List(parameters with { CouponID = couponID }, cancellationToken); + } +} diff --git a/src/Orb/Services/CreditNoteService.cs b/src/Orb/Services/CreditNoteService.cs new file mode 100644 index 00000000..03f82a39 --- /dev/null +++ b/src/Orb/Services/CreditNoteService.cs @@ -0,0 +1,118 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.CreditNotes; + +namespace Orb.Services; + +/// +public sealed class CreditNoteService : ICreditNoteService +{ + /// + public ICreditNoteService WithOptions(Func modifier) + { + return new CreditNoteService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public CreditNoteService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + CreditNoteCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var creditNote = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + creditNote.Validate(); + } + return creditNote; + } + + /// + public async Task List( + CreditNoteListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new CreditNoteListPage(this, parameters, page); + } + + /// + public async Task Fetch( + CreditNoteFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CreditNoteID == null) + { + throw new OrbInvalidDataException("'parameters.CreditNoteID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var creditNote = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + creditNote.Validate(); + } + return creditNote; + } + + /// + public async Task Fetch( + string creditNoteID, + CreditNoteFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { CreditNoteID = creditNoteID }, cancellationToken); + } +} diff --git a/src/Orb/Services/CustomerService.cs b/src/Orb/Services/CustomerService.cs new file mode 100644 index 00000000..5d1b4776 --- /dev/null +++ b/src/Orb/Services/CustomerService.cs @@ -0,0 +1,379 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers; +using Orb.Services.Customers; + +namespace Orb.Services; + +/// +public sealed class CustomerService : ICustomerService +{ + /// + public ICustomerService WithOptions(Func modifier) + { + return new CustomerService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public CustomerService(IOrbClient client) + { + _client = client; + _costs = new(() => new CostService(client)); + _credits = new(() => new CreditService(client)); + _balanceTransactions = new(() => new BalanceTransactionService(client)); + } + + readonly Lazy _costs; + public ICostService Costs + { + get { return _costs.Value; } + } + + readonly Lazy _credits; + public ICreditService Credits + { + get { return _credits.Value; } + } + + readonly Lazy _balanceTransactions; + public IBalanceTransactionService BalanceTransactions + { + get { return _balanceTransactions.Value; } + } + + /// + public async Task Create( + CustomerCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var customer = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + customer.Validate(); + } + return customer; + } + + /// + public async Task Update( + CustomerUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var customer = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + customer.Validate(); + } + return customer; + } + + /// + public async Task Update( + string customerID, + CustomerUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task List( + CustomerListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new CustomerListPage(this, parameters, page); + } + + /// + public async Task Delete( + CustomerDeleteParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Delete, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task Delete( + string customerID, + CustomerDeleteParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + await this.Delete(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task Fetch( + CustomerFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var customer = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + customer.Validate(); + } + return customer; + } + + /// + public async Task Fetch( + string customerID, + CustomerFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task FetchByExternalID( + CustomerFetchByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var customer = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + customer.Validate(); + } + return customer; + } + + /// + public async Task FetchByExternalID( + string externalCustomerID, + CustomerFetchByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.FetchByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } + + /// + public async Task SyncPaymentMethodsFromGateway( + CustomerSyncPaymentMethodsFromGatewayParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task SyncPaymentMethodsFromGateway( + string customerID, + CustomerSyncPaymentMethodsFromGatewayParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + await this.SyncPaymentMethodsFromGateway( + parameters with + { + CustomerID = customerID, + }, + cancellationToken + ); + } + + /// + public async Task SyncPaymentMethodsFromGatewayByExternalCustomerID( + CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task SyncPaymentMethodsFromGatewayByExternalCustomerID( + string externalCustomerID, + CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + await this.SyncPaymentMethodsFromGatewayByExternalCustomerID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } + + /// + public async Task UpdateByExternalID( + CustomerUpdateByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ID == null) + { + throw new OrbInvalidDataException("'parameters.ID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var customer = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + customer.Validate(); + } + return customer; + } + + /// + public async Task UpdateByExternalID( + string id, + CustomerUpdateByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.UpdateByExternalID(parameters with { ID = id }, cancellationToken); + } +} diff --git a/src/Orb/Services/Customers/BalanceTransactionService.cs b/src/Orb/Services/Customers/BalanceTransactionService.cs new file mode 100644 index 00000000..d929b17d --- /dev/null +++ b/src/Orb/Services/Customers/BalanceTransactionService.cs @@ -0,0 +1,106 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Services.Customers; + +/// +public sealed class BalanceTransactionService : IBalanceTransactionService +{ + /// + public IBalanceTransactionService WithOptions(Func modifier) + { + return new BalanceTransactionService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public BalanceTransactionService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + BalanceTransactionCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var balanceTransaction = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + balanceTransaction.Validate(); + } + return balanceTransaction; + } + + /// + public async Task Create( + string customerID, + BalanceTransactionCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.Create(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task List( + BalanceTransactionListParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new BalanceTransactionListPage(this, parameters, page); + } + + /// + public async Task List( + string customerID, + BalanceTransactionListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.List(parameters with { CustomerID = customerID }, cancellationToken); + } +} diff --git a/src/Orb/Services/Customers/CostService.cs b/src/Orb/Services/Customers/CostService.cs new file mode 100644 index 00000000..ea718558 --- /dev/null +++ b/src/Orb/Services/Customers/CostService.cs @@ -0,0 +1,114 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Costs; + +namespace Orb.Services.Customers; + +/// +public sealed class CostService : ICostService +{ + /// + public ICostService WithOptions(Func modifier) + { + return new CostService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public CostService(IOrbClient client) + { + _client = client; + } + + /// + public async Task List( + CostListParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var costs = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + costs.Validate(); + } + return costs; + } + + /// + public async Task List( + string customerID, + CostListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.List(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task ListByExternalID( + CostListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task ListByExternalID( + string externalCustomerID, + CostListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.ListByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Customers/CreditService.cs b/src/Orb/Services/Customers/CreditService.cs new file mode 100644 index 00000000..d0bcc7b7 --- /dev/null +++ b/src/Orb/Services/Customers/CreditService.cs @@ -0,0 +1,129 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits; +using Orb.Services.Customers.Credits; + +namespace Orb.Services.Customers; + +/// +public sealed class CreditService : ICreditService +{ + /// + public ICreditService WithOptions(Func modifier) + { + return new CreditService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public CreditService(IOrbClient client) + { + _client = client; + _ledger = new(() => new LedgerService(client)); + _topUps = new(() => new TopUpService(client)); + } + + readonly Lazy _ledger; + public ILedgerService Ledger + { + get { return _ledger.Value; } + } + + readonly Lazy _topUps; + public ITopUpService TopUps + { + get { return _topUps.Value; } + } + + /// + public async Task List( + CreditListParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new CreditListPage(this, parameters, page); + } + + /// + public async Task List( + string customerID, + CreditListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.List(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task ListByExternalID( + CreditListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new CreditListByExternalIDPage(this, parameters, page); + } + + /// + public async Task ListByExternalID( + string externalCustomerID, + CreditListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.ListByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Customers/Credits/ILedgerService.cs b/src/Orb/Services/Customers/Credits/ILedgerService.cs new file mode 100644 index 00000000..3dae9f5c --- /dev/null +++ b/src/Orb/Services/Customers/Credits/ILedgerService.cs @@ -0,0 +1,384 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Services.Customers.Credits; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ILedgerService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ILedgerService WithOptions(Func modifier); + + /// + /// The credits ledger provides _auditing_ functionality over Orb's credits system + /// with a list of actions that have taken place to modify a customer's credit + /// balance. This [paginated endpoint](/api-reference/pagination) lists these + /// entries, starting from the most recent ledger entry. + /// + /// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). + /// + /// There are four major types of modifications to credit balance, detailed below. + /// + /// ## Increment Credits (which optionally expire on a future date) can + /// be added via the API ([Add Ledger Entry](create-ledger-entry)). The ledger + /// entry for such an action will always contain the total eligible starting and + /// ending balance for the customer at the time the entry was added to the ledger. + /// + /// ## Decrement Deductions can occur as a result of an API call to create + /// a ledger entry (see [Add Ledger Entry](create-ledger-entry)), or automatically + /// as a result of incurring usage. Both ledger entries present the `decrement` + /// entry type. + /// + /// As usage for a customer is reported into Orb, credits may be deducted + /// according to the customer's plan configuration. An automated deduction of + /// this type will result in a ledger entry, also with a starting and ending balance. + /// In order to provide better tracing capabilities for automatic deductions, + /// Orb always associates each automatic deduction with the `event_id` at the + /// time of ingestion, used to pinpoint _why_ credit deduction took place and + /// to ensure that credits are never deducted without an associated usage event. + /// + /// By default, Orb uses an algorithm that automatically deducts from the + /// *soonest expiring credit block* first in order to ensure that all credits + /// are utilized appropriately. As an example, if trial credits with an expiration + /// date of 2 weeks from now are present for a customer, they will be used before + /// any deductions take place from a non-expiring credit block. + /// + /// If there are multiple blocks with the same expiration date, Orb will + /// deduct from the block with the *lower cost basis* first (e.g. trial credits + /// with a \$0 cost basis before paid credits with a \$5.00 cost basis). + /// + /// It's also possible for a single usage event's deduction to _span_ credit + /// blocks. In this case, Orb will deduct from the next block, ending at the + /// credit block which consists of unexpiring credits. Each of these deductions + /// will lead to a _separate_ ledger entry, one per credit block that is deducted + /// from. By default, the customer's total credit balance in Orb can be negative + /// as a result of a decrement. + /// + /// ## Expiration change The expiry of credits can be changed as a result + /// of the API (See [Add Ledger Entry](create-ledger-entry)). This will create + /// a ledger entry that specifies the balance as well as the initial and target + /// expiry dates. + /// + /// Note that for this entry type, `starting_balance` will equal `ending_balance`, + /// and the `amount` represents the balance transferred. The credit block linked + /// to the ledger entry is the source credit block from which there was an expiration change. + /// + /// ## Credits expiry When a set of credits expire on pre-set expiration + /// date, the customer's balance automatically reflects this change and adds + /// an entry to the ledger indicating this event. Note that credit expiry should + /// always happen close to a date boundary in the customer's timezone. + /// + /// ## Void initiated Credit blocks can be voided via the API. The `amount` + /// on this entry corresponds to the number of credits that were remaining in + /// the block at time of void. `void_reason` will be populated if the void is + /// created with a reason. + /// + /// ## Void When a set of credits is voided, the customer's balance automatically + /// reflects this change and adds an entry to the ledger indicating this event. + /// + /// ## Amendment When credits are added to a customer's balance as a result + /// of a correction, this entry will be added to the ledger to indicate the adjustment + /// of credits. + /// + Task List( + LedgerListParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task List( + string customerID, + LedgerListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to create a new ledger entry for a specified customer's + /// balance. This can be used to increment balance, deduct credits, and change + /// the expiry date of existing credits. + /// + /// ## Effects of adding a ledger entry 1. After calling this endpoint, + /// [Fetch Credit Balance](fetch-customer-credits) will return a credit block + /// that represents the changes (i.e. balance changes or transfers). 2. A ledger + /// entry will be added to the credits ledger for this customer, and therefore + /// returned in the [View Credits Ledger](fetch-customer-credits-ledger) response + /// as well as serialized in the response to this request. In the case of deductions + /// without a specified block, multiple ledger entries may be created if the deduction + /// spans credit blocks. 3. If `invoice_settings` is specified, an invoice + /// will be created that reflects the cost of the credits (based on `amount` + /// and `per_unit_cost_basis`). + /// + /// ## Adding credits Adding credits is done by creating an entry of + /// type `increment`. This requires the caller to specify a number of credits + /// as well as an optional expiry date in `YYYY-MM-DD` format. Orb also recommends + /// specifying a description to assist with auditing. When adding credits, the + /// caller can also specify a cost basis per-credit, to indicate how much in + /// USD a customer paid for a single credit in a block. This can later be used + /// for revenue recognition. + /// + /// The following snippet illustrates a sample request body to increment + /// credits which will expire in January of 2022. + /// + /// ```json { "entry_type": "increment", "amount": 100, "expiry_date": + /// "2022-12-28", "per_unit_cost_basis": "0.20", "description": "Purchased + /// 100 credits" } ``` + /// + /// Note that by default, Orb will always first increment any _negative_ + /// balance in existing blocks before adding the remaining amount to the desired + /// credit block. + /// + /// ### Invoicing for credits By default, Orb manipulates the credit ledger + /// but does not charge for credits. However, if you pass `invoice_settings` + /// in the body of this request, Orb will also generate a one-off invoice for + /// the customer for the credits pre-purchase. Note that you _must_ provide the + /// `per_unit_cost_basis`, since the total charges on the invoice are calculated + /// by multiplying the cost basis with the number of credit units added. + /// + /// ## Deducting Credits Orb allows you to deduct credits from a customer + /// by creating an entry of type `decrement`. Orb matches the algorithm for automatic + /// deductions for determining which credit blocks to decrement from. In the + /// case that the deduction leads to multiple ledger entries, the response from + /// this endpoint will be the final deduction. Orb also optionally allows specifying + /// a description to assist with auditing. + /// + /// The following snippet illustrates a sample request body to decrement credits. + /// + /// ```json { "entry_type": "decrement", "amount": 20, "description": + /// "Removing excess credits" } ``` + /// + /// ## Changing credits expiry If you'd like to change when existing credits + /// expire, you should create a ledger entry of type `expiration_change`. For + /// this entry, the required parameter `expiry_date` identifies the _originating_ + /// block, and the required parameter `target_expiry_date` identifies when the + /// transferred credits should now expire. A new credit block will be created + /// with expiry date `target_expiry_date`, with the same cost basis data as the + /// original credit block, if present. + /// + /// Note that the balance of the block with the given `expiry_date` must + /// be at least equal to the desired transfer amount determined by the `amount` parameter. + /// + /// The following snippet illustrates a sample request body to extend the + /// expiration date of credits by one year: + /// + /// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": + /// "2022-12-28", "block_id": "UiUhFWeLHPrBY4Ad", "target_expiry_date": "2023-12-28", + /// "description": "Extending credit validity" } ``` + /// + /// ## Voiding credits + /// + /// If you'd like to void a credit block, create a ledger entry of type + /// `void`. For this entry, `block_id` is required to identify the block, and + /// `amount` indicates how many credits to void, up to the block's initial balance. + /// Pass in a `void_reason` of `refund` if the void is due to a refund. + /// + /// ## Amendment + /// + /// If you'd like to undo a decrement on a credit block, create a ledger + /// entry of type `amendment`. For this entry, `block_id` is required to identify + /// the block that was originally decremented from, and `amount` indicates how + /// many credits to return to the customer, up to the block's initial balance. + /// + Task CreateEntry( + LedgerCreateEntryParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreateEntry( + string customerID, + LedgerCreateEntryParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to create a new ledger entry for a specified customer's + /// balance. This can be used to increment balance, deduct credits, and change + /// the expiry date of existing credits. + /// + /// ## Effects of adding a ledger entry 1. After calling this endpoint, + /// [Fetch Credit Balance](fetch-customer-credits) will return a credit block + /// that represents the changes (i.e. balance changes or transfers). 2. A ledger + /// entry will be added to the credits ledger for this customer, and therefore + /// returned in the [View Credits Ledger](fetch-customer-credits-ledger) response + /// as well as serialized in the response to this request. In the case of deductions + /// without a specified block, multiple ledger entries may be created if the deduction + /// spans credit blocks. 3. If `invoice_settings` is specified, an invoice + /// will be created that reflects the cost of the credits (based on `amount` + /// and `per_unit_cost_basis`). + /// + /// ## Adding credits Adding credits is done by creating an entry of + /// type `increment`. This requires the caller to specify a number of credits + /// as well as an optional expiry date in `YYYY-MM-DD` format. Orb also recommends + /// specifying a description to assist with auditing. When adding credits, the + /// caller can also specify a cost basis per-credit, to indicate how much in + /// USD a customer paid for a single credit in a block. This can later be used + /// for revenue recognition. + /// + /// The following snippet illustrates a sample request body to increment + /// credits which will expire in January of 2022. + /// + /// ```json { "entry_type": "increment", "amount": 100, "expiry_date": + /// "2022-12-28", "per_unit_cost_basis": "0.20", "description": "Purchased + /// 100 credits" } ``` + /// + /// Note that by default, Orb will always first increment any _negative_ + /// balance in existing blocks before adding the remaining amount to the desired + /// credit block. + /// + /// ### Invoicing for credits By default, Orb manipulates the credit ledger + /// but does not charge for credits. However, if you pass `invoice_settings` + /// in the body of this request, Orb will also generate a one-off invoice for + /// the customer for the credits pre-purchase. Note that you _must_ provide the + /// `per_unit_cost_basis`, since the total charges on the invoice are calculated + /// by multiplying the cost basis with the number of credit units added. + /// + /// ## Deducting Credits Orb allows you to deduct credits from a customer + /// by creating an entry of type `decrement`. Orb matches the algorithm for automatic + /// deductions for determining which credit blocks to decrement from. In the + /// case that the deduction leads to multiple ledger entries, the response from + /// this endpoint will be the final deduction. Orb also optionally allows specifying + /// a description to assist with auditing. + /// + /// The following snippet illustrates a sample request body to decrement credits. + /// + /// ```json { "entry_type": "decrement", "amount": 20, "description": + /// "Removing excess credits" } ``` + /// + /// ## Changing credits expiry If you'd like to change when existing credits + /// expire, you should create a ledger entry of type `expiration_change`. For + /// this entry, the required parameter `expiry_date` identifies the _originating_ + /// block, and the required parameter `target_expiry_date` identifies when the + /// transferred credits should now expire. A new credit block will be created + /// with expiry date `target_expiry_date`, with the same cost basis data as the + /// original credit block, if present. + /// + /// Note that the balance of the block with the given `expiry_date` must + /// be at least equal to the desired transfer amount determined by the `amount` parameter. + /// + /// The following snippet illustrates a sample request body to extend the + /// expiration date of credits by one year: + /// + /// ```json { "entry_type": "expiration_change", "amount": 10, "expiry_date": + /// "2022-12-28", "block_id": "UiUhFWeLHPrBY4Ad", "target_expiry_date": "2023-12-28", + /// "description": "Extending credit validity" } ``` + /// + /// ## Voiding credits + /// + /// If you'd like to void a credit block, create a ledger entry of type + /// `void`. For this entry, `block_id` is required to identify the block, and + /// `amount` indicates how many credits to void, up to the block's initial balance. + /// Pass in a `void_reason` of `refund` if the void is due to a refund. + /// + /// ## Amendment + /// + /// If you'd like to undo a decrement on a credit block, create a ledger + /// entry of type `amendment`. For this entry, `block_id` is required to identify + /// the block that was originally decremented from, and `amount` indicates how + /// many credits to return to the customer, up to the block's initial balance. + /// + Task CreateEntryByExternalID( + LedgerCreateEntryByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreateEntryByExternalID( + string externalCustomerID, + LedgerCreateEntryByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// The credits ledger provides _auditing_ functionality over Orb's credits system + /// with a list of actions that have taken place to modify a customer's credit + /// balance. This [paginated endpoint](/api-reference/pagination) lists these + /// entries, starting from the most recent ledger entry. + /// + /// More details on using Orb's real-time credit feature are [here](/product-catalog/prepurchase). + /// + /// There are four major types of modifications to credit balance, detailed below. + /// + /// ## Increment Credits (which optionally expire on a future date) can + /// be added via the API ([Add Ledger Entry](create-ledger-entry)). The ledger + /// entry for such an action will always contain the total eligible starting and + /// ending balance for the customer at the time the entry was added to the ledger. + /// + /// ## Decrement Deductions can occur as a result of an API call to create + /// a ledger entry (see [Add Ledger Entry](create-ledger-entry)), or automatically + /// as a result of incurring usage. Both ledger entries present the `decrement` + /// entry type. + /// + /// As usage for a customer is reported into Orb, credits may be deducted + /// according to the customer's plan configuration. An automated deduction of + /// this type will result in a ledger entry, also with a starting and ending balance. + /// In order to provide better tracing capabilities for automatic deductions, + /// Orb always associates each automatic deduction with the `event_id` at the + /// time of ingestion, used to pinpoint _why_ credit deduction took place and + /// to ensure that credits are never deducted without an associated usage event. + /// + /// By default, Orb uses an algorithm that automatically deducts from the + /// *soonest expiring credit block* first in order to ensure that all credits + /// are utilized appropriately. As an example, if trial credits with an expiration + /// date of 2 weeks from now are present for a customer, they will be used before + /// any deductions take place from a non-expiring credit block. + /// + /// If there are multiple blocks with the same expiration date, Orb will + /// deduct from the block with the *lower cost basis* first (e.g. trial credits + /// with a \$0 cost basis before paid credits with a \$5.00 cost basis). + /// + /// It's also possible for a single usage event's deduction to _span_ credit + /// blocks. In this case, Orb will deduct from the next block, ending at the + /// credit block which consists of unexpiring credits. Each of these deductions + /// will lead to a _separate_ ledger entry, one per credit block that is deducted + /// from. By default, the customer's total credit balance in Orb can be negative + /// as a result of a decrement. + /// + /// ## Expiration change The expiry of credits can be changed as a result + /// of the API (See [Add Ledger Entry](create-ledger-entry)). This will create + /// a ledger entry that specifies the balance as well as the initial and target + /// expiry dates. + /// + /// Note that for this entry type, `starting_balance` will equal `ending_balance`, + /// and the `amount` represents the balance transferred. The credit block linked + /// to the ledger entry is the source credit block from which there was an expiration change. + /// + /// ## Credits expiry When a set of credits expire on pre-set expiration + /// date, the customer's balance automatically reflects this change and adds + /// an entry to the ledger indicating this event. Note that credit expiry should + /// always happen close to a date boundary in the customer's timezone. + /// + /// ## Void initiated Credit blocks can be voided via the API. The `amount` + /// on this entry corresponds to the number of credits that were remaining in + /// the block at time of void. `void_reason` will be populated if the void is + /// created with a reason. + /// + /// ## Void When a set of credits is voided, the customer's balance automatically + /// reflects this change and adds an entry to the ledger indicating this event. + /// + /// ## Amendment When credits are added to a customer's balance as a result + /// of a correction, this entry will be added to the ledger to indicate the adjustment + /// of credits. + /// + Task ListByExternalID( + LedgerListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task ListByExternalID( + string externalCustomerID, + LedgerListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Customers/Credits/ITopUpService.cs b/src/Orb/Services/Customers/Credits/ITopUpService.cs new file mode 100644 index 00000000..6fae287e --- /dev/null +++ b/src/Orb/Services/Customers/Credits/ITopUpService.cs @@ -0,0 +1,121 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Services.Customers.Credits; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ITopUpService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ITopUpService WithOptions(Func modifier); + + /// + /// This endpoint allows you to create a new top-up for a specified customer's + /// balance. While this top-up is active, the customer's balance will added in + /// increments of the specified amount whenever the balance reaches the specified threshold. + /// + /// If a top-up already exists for this customer in the same currency, + /// the existing top-up will be replaced. + /// + Task Create( + TopUpCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Create( + string customerID, + TopUpCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// List top-ups + /// + Task List( + TopUpListParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task List( + string customerID, + TopUpListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This deactivates the top-up and voids any invoices associated with pending + /// credit blocks purchased through the top-up. + /// + Task Delete(TopUpDeleteParams parameters, CancellationToken cancellationToken = default); + + /// + Task Delete( + string topUpID, + TopUpDeleteParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to create a new top-up for a specified customer's + /// balance. While this top-up is active, the customer's balance will added in + /// increments of the specified amount whenever the balance reaches the specified threshold. + /// + /// If a top-up already exists for this customer in the same currency, + /// the existing top-up will be replaced. + /// + Task CreateByExternalID( + TopUpCreateByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreateByExternalID( + string externalCustomerID, + TopUpCreateByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This deactivates the top-up and voids any invoices associated with pending + /// credit blocks purchased through the top-up. + /// + Task DeleteByExternalID( + TopUpDeleteByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task DeleteByExternalID( + string topUpID, + TopUpDeleteByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// List top-ups by external ID + /// + Task ListByExternalID( + TopUpListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task ListByExternalID( + string externalCustomerID, + TopUpListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Customers/Credits/LedgerService.cs b/src/Orb/Services/Customers/Credits/LedgerService.cs new file mode 100644 index 00000000..677bd6b0 --- /dev/null +++ b/src/Orb/Services/Customers/Credits/LedgerService.cs @@ -0,0 +1,204 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.Ledger; + +namespace Orb.Services.Customers.Credits; + +/// +public sealed class LedgerService : ILedgerService +{ + /// + public ILedgerService WithOptions(Func modifier) + { + return new LedgerService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public LedgerService(IOrbClient client) + { + _client = client; + } + + /// + public async Task List( + LedgerListParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new LedgerListPage(this, parameters, page); + } + + /// + public async Task List( + string customerID, + LedgerListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.List(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task CreateEntry( + LedgerCreateEntryParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task CreateEntry( + string customerID, + LedgerCreateEntryParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreateEntry( + parameters with + { + CustomerID = customerID, + }, + cancellationToken + ); + } + + /// + public async Task CreateEntryByExternalID( + LedgerCreateEntryByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task CreateEntryByExternalID( + string externalCustomerID, + LedgerCreateEntryByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreateEntryByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } + + /// + public async Task ListByExternalID( + LedgerListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new LedgerListByExternalIDPage(this, parameters, page); + } + + /// + public async Task ListByExternalID( + string externalCustomerID, + LedgerListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.ListByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Customers/Credits/TopUpService.cs b/src/Orb/Services/Customers/Credits/TopUpService.cs new file mode 100644 index 00000000..350a6be8 --- /dev/null +++ b/src/Orb/Services/Customers/Credits/TopUpService.cs @@ -0,0 +1,260 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Customers.Credits.TopUps; + +namespace Orb.Services.Customers.Credits; + +/// +public sealed class TopUpService : ITopUpService +{ + /// + public ITopUpService WithOptions(Func modifier) + { + return new TopUpService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public TopUpService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + TopUpCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var topUp = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + topUp.Validate(); + } + return topUp; + } + + /// + public async Task Create( + string customerID, + TopUpCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.Create(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task List( + TopUpListParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.CustomerID == null) + { + throw new OrbInvalidDataException("'parameters.CustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new TopUpListPage(this, parameters, page); + } + + /// + public async Task List( + string customerID, + TopUpListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.List(parameters with { CustomerID = customerID }, cancellationToken); + } + + /// + public async Task Delete( + TopUpDeleteParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.TopUpID == null) + { + throw new OrbInvalidDataException("'parameters.TopUpID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Delete, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task Delete( + string topUpID, + TopUpDeleteParams parameters, + CancellationToken cancellationToken = default + ) + { + await this.Delete(parameters with { TopUpID = topUpID }, cancellationToken); + } + + /// + public async Task CreateByExternalID( + TopUpCreateByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task CreateByExternalID( + string externalCustomerID, + TopUpCreateByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.CreateByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } + + /// + public async Task DeleteByExternalID( + TopUpDeleteByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.TopUpID == null) + { + throw new OrbInvalidDataException("'parameters.TopUpID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Delete, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + } + + /// + public async Task DeleteByExternalID( + string topUpID, + TopUpDeleteByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + await this.DeleteByExternalID(parameters with { TopUpID = topUpID }, cancellationToken); + } + + /// + public async Task ListByExternalID( + TopUpListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalCustomerID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalCustomerID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new TopUpListByExternalIDPage(this, parameters, page); + } + + /// + public async Task ListByExternalID( + string externalCustomerID, + TopUpListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.ListByExternalID( + parameters with + { + ExternalCustomerID = externalCustomerID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Customers/IBalanceTransactionService.cs b/src/Orb/Services/Customers/IBalanceTransactionService.cs new file mode 100644 index 00000000..6b12ba33 --- /dev/null +++ b/src/Orb/Services/Customers/IBalanceTransactionService.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Customers.BalanceTransactions; + +namespace Orb.Services.Customers; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IBalanceTransactionService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IBalanceTransactionService WithOptions(Func modifier); + + /// + /// Creates an immutable balance transaction that updates the customer's balance + /// and returns back the newly created transaction. + /// + Task Create( + BalanceTransactionCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Create( + string customerID, + BalanceTransactionCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// ## The customer balance + /// + /// The customer balance is an amount in the customer's currency, which + /// Orb automatically applies to subsequent invoices. This balance can be adjusted + /// manually via Orb's webapp on the customer details page. You can use this balance + /// to provide a fixed mid-period credit to the customer. Commonly, this is done + /// due to system downtime/SLA violation, or an adhoc adjustment discussed with + /// the customer. + /// + /// If the balance is a positive value at the time of invoicing, it represents + /// that the customer has credit that should be used to offset the amount due + /// on the next issued invoice. In this case, Orb will automatically reduce the + /// next invoice by the balance amount, and roll over any remaining balance if + /// the invoice is fully discounted. + /// + /// If the balance is a negative value at the time of invoicing, Orb will + /// increase the invoice's amount due with a positive adjustment, and reset the + /// balance to 0. + /// + /// This endpoint retrieves all customer balance transactions in reverse + /// chronological order for a single customer, providing a complete audit trail + /// of all adjustments and invoice applications. + /// + Task List( + BalanceTransactionListParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task List( + string customerID, + BalanceTransactionListParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Customers/ICostService.cs b/src/Orb/Services/Customers/ICostService.cs new file mode 100644 index 00000000..f5b99a0a --- /dev/null +++ b/src/Orb/Services/Customers/ICostService.cs @@ -0,0 +1,244 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Customers.Costs; + +namespace Orb.Services.Customers; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ICostService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ICostService WithOptions(Func modifier); + + /// + /// This endpoint is used to fetch a day-by-day snapshot of a customer's costs + /// in Orb, calculated by applying pricing information to the underlying usage + /// (see the [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) + /// to fetch usage per metric, in usage units rather than a currency). + /// + /// This endpoint can be leveraged for internal tooling and to provide a + /// more transparent billing experience for your end users: + /// + /// 1. Understand the cost breakdown per line item historically and in real-time + /// for the current billing period. 2. Provide customer visibility into how different + /// services are contributing to the overall invoice with a per-day timeseries + /// (as compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) + /// resource, which represents a snapshot for the current period). 3. Assess + /// how minimums and discounts affect your customers by teasing apart costs directly + /// as a result of usage, as opposed to minimums and discounts at the plan + /// and price level. 4. Gain insight into key customer health metrics, such as + /// the percent utilization of the minimum committed spend. + /// + /// ## Fetching subscriptions By default, this endpoint fetches the currently + /// active subscription for the customer, and returns cost information for the + /// subscription's current billing period, broken down by each participating + /// price. If there are no currently active subscriptions, this will instead default + /// to the most recently active subscription or return an empty series if none + /// are found. For example, if your plan charges for compute hours, job runs, + /// and data syncs, then this endpoint would provide a daily breakdown of your + /// customer's cost for each of those axes. + /// + /// If timeframe bounds are specified, Orb fetches all subscriptions that + /// were active in that timeframe. If two subscriptions overlap on a single day, + /// costs from each price will be summed, and prices for both subscriptions will + /// be included in the breakdown. + /// + /// ## Prepaid plans For plans that include prices which deduct credits + /// rather than accrue in-arrears charges in a billable currency, this endpoint + /// will return the total deduction amount, in credits, for the specified timeframe. + /// + /// ## Cumulative subtotals and totals Since the subtotal and total must + /// factor in any billing-period level discounts and minimums, it's most meaningful + /// to consider costs relative to the start of the subscription's billing period. + /// As a result, by default this endpoint returns cumulative totals since the + /// beginning of the billing period. In particular, the `timeframe_start` of + /// a returned timeframe window is *always* the beginning of the billing period + /// and `timeframe_end` is incremented one day at a time to build the result. + /// + /// A customer that uses a few API calls a day but has a minimum commitment + /// might exhibit the following pattern for their subtotal and total in the first + /// few days of the month. Here, we assume that each API call is \$2.50, the customer's + /// plan has a monthly minimum of \$50 for this price, and that the subscription's + /// billing period bounds are aligned to the first of the month: + /// + /// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total + /// (incl. commitment) | | -----------| ----------- | ----------- | ----------- + /// |----------- | | 2023-02-01 | 2023-02-02 | 9 | \$22.50 | \$50.00 | | 2023-02-01 + /// | 2023-02-03 | 19 | \$47.50 | \$50.00 | | 2023-02-01 | 2023-02-04 | 20 | + /// \$50.00 | \$50.00 | | 2023-02-01 | 2023-02-05 | 28 | \$70.00 | \$70.00 | | + /// 2023-02-01 | 2023-02-06 | 36 | \$90.00 | \$90.00 | + /// + /// ### Periodic values When the query parameter `view_mode=periodic` is + /// specified, Orb will return an incremental day-by-day view of costs. In this + /// case, there will always be a one-day difference between `timeframe_start` + /// and `timeframe_end` for the timeframes returned. This is a transform on top + /// of the cumulative costs, calculated by taking the difference of each timeframe + /// with the last. Note that in the above example, the `Total` value would be + /// 0 for the second two data points, since the minimum commitment has not yet + /// been hit and each day is not contributing anything to the total cost. + /// + /// ## Timeframe bounds For an active subscription, both timeframes should + /// be specified in the request. If a subscription starts or ends within the timeframe, + /// the response will only include windows where the subscription is active. If + /// a subscription has ended, no timeframe bounds need to be specified and the + /// response will default to the billing period when the subscription was last active. + /// + /// As noted above, `timeframe_start` for a given cumulative datapoint is + /// always the beginning of the billing period, and `timeframe_end` is incremented + /// one day at a time to construct the response. When a timeframe is passed in + /// that is not aligned to the current subscription's billing period, the response + /// will contain cumulative totals from multiple billing periods. + /// + /// Suppose the queried customer has a subscription aligned to the 15th + /// of every month. If this endpoint is queried with the date range `2023-06-01` + /// - `2023-07-01`, the first data point will represent about half a billing + /// period's worth of costs, accounting for accruals from the start of the billing + /// period and inclusive of the first day of the timeframe (`timeframe_start + /// = 2023-05-15 00:00:00`, `timeframe_end = 2023-06-02 00:00:00`) + /// + /// | datapoint index | timeframe_start | timeframe_end | | ----------- + /// | -----------| ----------- | | 0 | 2023-05-15 | 2023-06-02 | | 1 | 2023-05-15 + /// | 2023-06-03 | | 2 | ... | ... | | 3 | 2023-05-15 | 2023-06-14 | | 4 | 2023-06-15 + /// | 2023-06-16 | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 + /// | 2023-07-01 | + /// + /// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). + /// + /// ### Matrix prices When a price uses matrix pricing, it's important to + /// view costs grouped by those matrix dimensions. Orb will return `price_groups` + /// with the `grouping_key` and `secondary_grouping_key` based on the matrix + /// price definition, for each `grouping_value` and `secondary_grouping_value` available. + /// + Task List( + CostListParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task List( + string customerID, + CostListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a day-by-day snapshot of a customer's costs + /// in Orb, calculated by applying pricing information to the underlying usage + /// (see the [subscription usage endpoint](/api-reference/subscription/fetch-subscription-usage) + /// to fetch usage per metric, in usage units rather than a currency). + /// + /// This endpoint can be leveraged for internal tooling and to provide a + /// more transparent billing experience for your end users: + /// + /// 1. Understand the cost breakdown per line item historically and in real-time + /// for the current billing period. 2. Provide customer visibility into how different + /// services are contributing to the overall invoice with a per-day timeseries + /// (as compared to the [upcoming invoice](/api-reference/invoice/fetch-upcoming-invoice) + /// resource, which represents a snapshot for the current period). 3. Assess + /// how minimums and discounts affect your customers by teasing apart costs directly + /// as a result of usage, as opposed to minimums and discounts at the plan + /// and price level. 4. Gain insight into key customer health metrics, such as + /// the percent utilization of the minimum committed spend. + /// + /// ## Fetching subscriptions By default, this endpoint fetches the currently + /// active subscription for the customer, and returns cost information for the + /// subscription's current billing period, broken down by each participating + /// price. If there are no currently active subscriptions, this will instead default + /// to the most recently active subscription or return an empty series if none + /// are found. For example, if your plan charges for compute hours, job runs, + /// and data syncs, then this endpoint would provide a daily breakdown of your + /// customer's cost for each of those axes. + /// + /// If timeframe bounds are specified, Orb fetches all subscriptions that + /// were active in that timeframe. If two subscriptions overlap on a single day, + /// costs from each price will be summed, and prices for both subscriptions will + /// be included in the breakdown. + /// + /// ## Prepaid plans For plans that include prices which deduct credits + /// rather than accrue in-arrears charges in a billable currency, this endpoint + /// will return the total deduction amount, in credits, for the specified timeframe. + /// + /// ## Cumulative subtotals and totals Since the subtotal and total must + /// factor in any billing-period level discounts and minimums, it's most meaningful + /// to consider costs relative to the start of the subscription's billing period. + /// As a result, by default this endpoint returns cumulative totals since the + /// beginning of the billing period. In particular, the `timeframe_start` of + /// a returned timeframe window is *always* the beginning of the billing period + /// and `timeframe_end` is incremented one day at a time to build the result. + /// + /// A customer that uses a few API calls a day but has a minimum commitment + /// might exhibit the following pattern for their subtotal and total in the first + /// few days of the month. Here, we assume that each API call is \$2.50, the customer's + /// plan has a monthly minimum of \$50 for this price, and that the subscription's + /// billing period bounds are aligned to the first of the month: + /// + /// | timeframe_start | timeframe_end | Cumulative usage | Subtotal | Total + /// (incl. commitment) | | -----------| ----------- | ----------- | ----------- + /// |----------- | | 2023-02-01 | 2023-02-02 | 9 | \$22.50 | \$50.00 | | 2023-02-01 + /// | 2023-02-03 | 19 | \$47.50 | \$50.00 | | 2023-02-01 | 2023-02-04 | 20 | + /// \$50.00 | \$50.00 | | 2023-02-01 | 2023-02-05 | 28 | \$70.00 | \$70.00 | | + /// 2023-02-01 | 2023-02-06 | 36 | \$90.00 | \$90.00 | + /// + /// ### Periodic values When the query parameter `view_mode=periodic` is + /// specified, Orb will return an incremental day-by-day view of costs. In this + /// case, there will always be a one-day difference between `timeframe_start` + /// and `timeframe_end` for the timeframes returned. This is a transform on top + /// of the cumulative costs, calculated by taking the difference of each timeframe + /// with the last. Note that in the above example, the `Total` value would be + /// 0 for the second two data points, since the minimum commitment has not yet + /// been hit and each day is not contributing anything to the total cost. + /// + /// ## Timeframe bounds For an active subscription, both timeframes should + /// be specified in the request. If a subscription starts or ends within the timeframe, + /// the response will only include windows where the subscription is active. If + /// a subscription has ended, no timeframe bounds need to be specified and the + /// response will default to the billing period when the subscription was last active. + /// + /// As noted above, `timeframe_start` for a given cumulative datapoint is + /// always the beginning of the billing period, and `timeframe_end` is incremented + /// one day at a time to construct the response. When a timeframe is passed in + /// that is not aligned to the current subscription's billing period, the response + /// will contain cumulative totals from multiple billing periods. + /// + /// Suppose the queried customer has a subscription aligned to the 15th + /// of every month. If this endpoint is queried with the date range `2023-06-01` + /// - `2023-07-01`, the first data point will represent about half a billing + /// period's worth of costs, accounting for accruals from the start of the billing + /// period and inclusive of the first day of the timeframe (`timeframe_start + /// = 2023-05-15 00:00:00`, `timeframe_end = 2023-06-02 00:00:00`) + /// + /// | datapoint index | timeframe_start | timeframe_end | | ----------- + /// | -----------| ----------- | | 0 | 2023-05-15 | 2023-06-02 | | 1 | 2023-05-15 + /// | 2023-06-03 | | 2 | ... | ... | | 3 | 2023-05-15 | 2023-06-14 | | 4 | 2023-06-15 + /// | 2023-06-16 | | 5 | 2023-06-15 | 2023-06-17 | | 6 | ... | ... | | 7 | 2023-06-15 + /// | 2023-07-01 | + /// + /// You can see this sliced timeframe visualized [here](https://i.imgur.com/TXhYgme.png). + /// + /// ### Matrix prices When a price uses matrix pricing, it's important to + /// view costs grouped by those matrix dimensions. Orb will return `price_groups` + /// with the `grouping_key` and `secondary_grouping_key` based on the matrix + /// price definition, for each `grouping_value` and `secondary_grouping_value` available. + /// + Task ListByExternalID( + CostListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task ListByExternalID( + string externalCustomerID, + CostListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Customers/ICreditService.cs b/src/Orb/Services/Customers/ICreditService.cs new file mode 100644 index 00000000..e0ebe85e --- /dev/null +++ b/src/Orb/Services/Customers/ICreditService.cs @@ -0,0 +1,69 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Customers.Credits; +using Orb.Services.Customers.Credits; + +namespace Orb.Services.Customers; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ICreditService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ICreditService WithOptions(Func modifier); + + ILedgerService Ledger { get; } + + ITopUpService TopUps { get; } + + /// + /// Returns a paginated list of unexpired, non-zero credit blocks for a customer. + /// + /// If `include_all_blocks` is set to `true`, all credit blocks (including + /// expired and depleted blocks) will be included in the response. + /// + /// Note that `currency` defaults to credits if not specified. To use a + /// real world currency, set `currency` to an ISO 4217 string. + /// + Task List( + CreditListParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task List( + string customerID, + CreditListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Returns a paginated list of unexpired, non-zero credit blocks for a customer. + /// + /// If `include_all_blocks` is set to `true`, all credit blocks (including + /// expired and depleted blocks) will be included in the response. + /// + /// Note that `currency` defaults to credits if not specified. To use a + /// real world currency, set `currency` to an ISO 4217 string. + /// + Task ListByExternalID( + CreditListByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task ListByExternalID( + string externalCustomerID, + CreditListByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/DimensionalPriceGroupService.cs b/src/Orb/Services/DimensionalPriceGroupService.cs new file mode 100644 index 00000000..26f0f0de --- /dev/null +++ b/src/Orb/Services/DimensionalPriceGroupService.cs @@ -0,0 +1,184 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.DimensionalPriceGroups; +using Orb.Services.DimensionalPriceGroups; + +namespace Orb.Services; + +/// +public sealed class DimensionalPriceGroupService : IDimensionalPriceGroupService +{ + /// + public IDimensionalPriceGroupService WithOptions(Func modifier) + { + return new DimensionalPriceGroupService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public DimensionalPriceGroupService(IOrbClient client) + { + _client = client; + _externalDimensionalPriceGroupID = new(() => + new ExternalDimensionalPriceGroupIDService(client) + ); + } + + readonly Lazy _externalDimensionalPriceGroupID; + public IExternalDimensionalPriceGroupIDService ExternalDimensionalPriceGroupID + { + get { return _externalDimensionalPriceGroupID.Value; } + } + + /// + public async Task Create( + DimensionalPriceGroupCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var dimensionalPriceGroup = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + dimensionalPriceGroup.Validate(); + } + return dimensionalPriceGroup; + } + + /// + public async Task Retrieve( + DimensionalPriceGroupRetrieveParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.DimensionalPriceGroupID == null) + { + throw new OrbInvalidDataException( + "'parameters.DimensionalPriceGroupID' cannot be null" + ); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var dimensionalPriceGroup = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + dimensionalPriceGroup.Validate(); + } + return dimensionalPriceGroup; + } + + /// + public async Task Retrieve( + string dimensionalPriceGroupID, + DimensionalPriceGroupRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Retrieve( + parameters with + { + DimensionalPriceGroupID = dimensionalPriceGroupID, + }, + cancellationToken + ); + } + + /// + public async Task Update( + DimensionalPriceGroupUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.DimensionalPriceGroupID == null) + { + throw new OrbInvalidDataException( + "'parameters.DimensionalPriceGroupID' cannot be null" + ); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var dimensionalPriceGroup = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + dimensionalPriceGroup.Validate(); + } + return dimensionalPriceGroup; + } + + /// + public async Task Update( + string dimensionalPriceGroupID, + DimensionalPriceGroupUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update( + parameters with + { + DimensionalPriceGroupID = dimensionalPriceGroupID, + }, + cancellationToken + ); + } + + /// + public async Task List( + DimensionalPriceGroupListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new DimensionalPriceGroupListPage(this, parameters, page); + } +} diff --git a/src/Orb/Services/DimensionalPriceGroups/ExternalDimensionalPriceGroupIDService.cs b/src/Orb/Services/DimensionalPriceGroups/ExternalDimensionalPriceGroupIDService.cs new file mode 100644 index 00000000..2de5d732 --- /dev/null +++ b/src/Orb/Services/DimensionalPriceGroups/ExternalDimensionalPriceGroupIDService.cs @@ -0,0 +1,127 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.DimensionalPriceGroups; +using Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +namespace Orb.Services.DimensionalPriceGroups; + +/// +public sealed class ExternalDimensionalPriceGroupIDService : IExternalDimensionalPriceGroupIDService +{ + /// + public IExternalDimensionalPriceGroupIDService WithOptions( + Func modifier + ) + { + return new ExternalDimensionalPriceGroupIDService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public ExternalDimensionalPriceGroupIDService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Retrieve( + ExternalDimensionalPriceGroupIDRetrieveParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalDimensionalPriceGroupID == null) + { + throw new OrbInvalidDataException( + "'parameters.ExternalDimensionalPriceGroupID' cannot be null" + ); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var dimensionalPriceGroup = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + dimensionalPriceGroup.Validate(); + } + return dimensionalPriceGroup; + } + + /// + public async Task Retrieve( + string externalDimensionalPriceGroupID, + ExternalDimensionalPriceGroupIDRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Retrieve( + parameters with + { + ExternalDimensionalPriceGroupID = externalDimensionalPriceGroupID, + }, + cancellationToken + ); + } + + /// + public async Task Update( + ExternalDimensionalPriceGroupIDUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalDimensionalPriceGroupID == null) + { + throw new OrbInvalidDataException( + "'parameters.ExternalDimensionalPriceGroupID' cannot be null" + ); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var dimensionalPriceGroup = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + dimensionalPriceGroup.Validate(); + } + return dimensionalPriceGroup; + } + + /// + public async Task Update( + string externalDimensionalPriceGroupID, + ExternalDimensionalPriceGroupIDUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update( + parameters with + { + ExternalDimensionalPriceGroupID = externalDimensionalPriceGroupID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/DimensionalPriceGroups/IExternalDimensionalPriceGroupIDService.cs b/src/Orb/Services/DimensionalPriceGroups/IExternalDimensionalPriceGroupIDService.cs new file mode 100644 index 00000000..ca942078 --- /dev/null +++ b/src/Orb/Services/DimensionalPriceGroups/IExternalDimensionalPriceGroupIDService.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.DimensionalPriceGroups; +using Orb.Models.DimensionalPriceGroups.ExternalDimensionalPriceGroupID; + +namespace Orb.Services.DimensionalPriceGroups; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IExternalDimensionalPriceGroupIDService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IExternalDimensionalPriceGroupIDService WithOptions( + Func modifier + ); + + /// + /// Fetch dimensional price group by external ID + /// + Task Retrieve( + ExternalDimensionalPriceGroupIDRetrieveParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Retrieve( + string externalDimensionalPriceGroupID, + ExternalDimensionalPriceGroupIDRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to update the `external_dimensional_price_group_id` + /// and `metadata` of an existing dimensional price group. Other fields on a dimensional + /// price group are currently immutable. + /// + Task Update( + ExternalDimensionalPriceGroupIDUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string externalDimensionalPriceGroupID, + ExternalDimensionalPriceGroupIDUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/EventService.cs b/src/Orb/Services/EventService.cs new file mode 100644 index 00000000..e5647e3f --- /dev/null +++ b/src/Orb/Services/EventService.cs @@ -0,0 +1,169 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events; +using Orb.Services.Events; + +namespace Orb.Services; + +/// +public sealed class EventService : IEventService +{ + /// + public IEventService WithOptions(Func modifier) + { + return new EventService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public EventService(IOrbClient client) + { + _client = client; + _backfills = new(() => new BackfillService(client)); + _volume = new(() => new VolumeService(client)); + } + + readonly Lazy _backfills; + public IBackfillService Backfills + { + get { return _backfills.Value; } + } + + readonly Lazy _volume; + public IVolumeService Volume + { + get { return _volume.Value; } + } + + /// + public async Task Update( + EventUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.EventID == null) + { + throw new OrbInvalidDataException("'parameters.EventID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Update( + string eventID, + EventUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.Update(parameters with { EventID = eventID }, cancellationToken); + } + + /// + public async Task Deprecate( + EventDeprecateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.EventID == null) + { + throw new OrbInvalidDataException("'parameters.EventID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Deprecate( + string eventID, + EventDeprecateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Deprecate(parameters with { EventID = eventID }, cancellationToken); + } + + /// + public async Task Ingest( + EventIngestParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Search( + EventSearchParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } +} diff --git a/src/Orb/Services/Events/BackfillService.cs b/src/Orb/Services/Events/BackfillService.cs new file mode 100644 index 00000000..745f6312 --- /dev/null +++ b/src/Orb/Services/Events/BackfillService.cs @@ -0,0 +1,199 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Events.Backfills; + +namespace Orb.Services.Events; + +/// +public sealed class BackfillService : IBackfillService +{ + /// + public IBackfillService WithOptions(Func modifier) + { + return new BackfillService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public BackfillService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + BackfillCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var backfill = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + backfill.Validate(); + } + return backfill; + } + + /// + public async Task List( + BackfillListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new BackfillListPage(this, parameters, page); + } + + /// + public async Task Close( + BackfillCloseParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.BackfillID == null) + { + throw new OrbInvalidDataException("'parameters.BackfillID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Close( + string backfillID, + BackfillCloseParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Close(parameters with { BackfillID = backfillID }, cancellationToken); + } + + /// + public async Task Fetch( + BackfillFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.BackfillID == null) + { + throw new OrbInvalidDataException("'parameters.BackfillID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Fetch( + string backfillID, + BackfillFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { BackfillID = backfillID }, cancellationToken); + } + + /// + public async Task Revert( + BackfillRevertParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.BackfillID == null) + { + throw new OrbInvalidDataException("'parameters.BackfillID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Revert( + string backfillID, + BackfillRevertParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Revert(parameters with { BackfillID = backfillID }, cancellationToken); + } +} diff --git a/src/Orb/Services/Events/IBackfillService.cs b/src/Orb/Services/Events/IBackfillService.cs new file mode 100644 index 00000000..1d8b68a2 --- /dev/null +++ b/src/Orb/Services/Events/IBackfillService.cs @@ -0,0 +1,133 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Events.Backfills; + +namespace Orb.Services.Events; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IBackfillService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IBackfillService WithOptions(Func modifier); + + /// + /// Creating the backfill enables adding or replacing past events, even those + /// that are older than the ingestion grace period. Performing a backfill in Orb + /// involves 3 steps: + /// + /// 1. Create the backfill, specifying its parameters. 2. [Ingest](ingest) + /// usage events, referencing the backfill (query parameter `backfill_id`). 3. + /// [Close](close-backfill) the backfill, propagating the update in past usage + /// throughout Orb. + /// + /// Changes from a backfill are not reflected until the backfill is closed, + /// so you won’t need to worry about your customers seeing partially updated + /// usage data. Backfills are also reversible, so you’ll be able to revert a backfill + /// if you’ve made a mistake. + /// + /// This endpoint will return a backfill object, which contains an `id`. + /// That `id` can then be used as the `backfill_id` query parameter to the event + /// ingestion endpoint to associate ingested events with this backfill. The effects + /// (e.g. updated usage graphs) of this backfill will not take place until the + /// backfill is closed. + /// + /// If the `replace_existing_events` is `true`, existing events in the backfill's + /// timeframe will be replaced with the newly ingested events associated with + /// the backfill. If `false`, newly ingested events will be added to the existing events. + /// + /// If a `customer_id` or `external_customer_id` is specified, the backfill + /// will only affect events for that customer. If neither is specified, the backfill + /// will affect all customers. + /// + /// When `replace_existing_events` is `true`, this indicates that existing + /// events in the timeframe should no longer be counted towards invoiced usage. + /// In this scenario, the parameter `deprecation_filter` can be optionally added + /// which enables filtering using [computed properties](/extensibility/advanced-metrics#computed-properties). + /// The expressiveness of computed properties allows you to deprecate existing + /// events based on both a period of time and specific property values. + /// + /// You may not have multiple backfills in a pending or pending_revert state + /// with overlapping timeframes. + /// + Task Create( + BackfillCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all backfills in a list format. + /// + /// The list of backfills is ordered starting from the most recently created + /// backfill. The response also includes [`pagination_metadata`](/api-reference/pagination), + /// which lets the caller retrieve the next page of results if they exist. More + /// information about pagination can be found in the [Pagination-metadata schema](pagination). + /// + Task List( + BackfillListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Closing a backfill makes the updated usage visible in Orb. Upon closing a + /// backfill, Orb will asynchronously reflect the updated usage in invoice amounts + /// and usage graphs. Once all of the updates are complete, the backfill's status + /// will transition to `reflected`. + /// + Task Close( + BackfillCloseParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Close( + string backfillID, + BackfillCloseParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a backfill given an identifier. + /// + Task Fetch( + BackfillFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string backfillID, + BackfillFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Reverting a backfill undoes all the effects of closing the backfill. If the + /// backfill is reflected, the status will transition to `pending_revert` while + /// the effects of the backfill are undone. Once all effects are undone, the + /// backfill will transition to `reverted`. + /// + /// If a backfill is reverted before its closed, no usage will be updated + /// as a result of the backfill and it will immediately transition to `reverted`. + /// + Task Revert( + BackfillRevertParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Revert( + string backfillID, + BackfillRevertParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Events/IVolumeService.cs b/src/Orb/Services/Events/IVolumeService.cs new file mode 100644 index 00000000..ddf53f6f --- /dev/null +++ b/src/Orb/Services/Events/IVolumeService.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Events.Volume; + +namespace Orb.Services.Events; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IVolumeService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IVolumeService WithOptions(Func modifier); + + /// + /// This endpoint returns the event volume for an account in a [paginated list format](/api-reference/pagination). + /// + /// The event volume is aggregated by the hour and the [timestamp](/api-reference/event/ingest-events) + /// field is used to determine which hour an event is associated with. Note, + /// this means that late-arriving events increment the volume count for the hour + /// window the timestamp is in, not the latest hour window. + /// + /// Each item in the response contains the count of events aggregated by + /// the hour where the start and end time are hour-aligned and in UTC. When a + /// specific timestamp is passed in for either start or end time, the response + /// includes the hours the timestamp falls in. + /// + Task List( + VolumeListParams parameters, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/Events/VolumeService.cs b/src/Orb/Services/Events/VolumeService.cs new file mode 100644 index 00000000..756d60c1 --- /dev/null +++ b/src/Orb/Services/Events/VolumeService.cs @@ -0,0 +1,49 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Events.Volume; + +namespace Orb.Services.Events; + +/// +public sealed class VolumeService : IVolumeService +{ + /// + public IVolumeService WithOptions(Func modifier) + { + return new VolumeService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public VolumeService(IOrbClient client) + { + _client = client; + } + + /// + public async Task List( + VolumeListParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var eventVolumes = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + eventVolumes.Validate(); + } + return eventVolumes; + } +} diff --git a/src/Orb/Services/IAlertService.cs b/src/Orb/Services/IAlertService.cs new file mode 100644 index 00000000..cb67d432 --- /dev/null +++ b/src/Orb/Services/IAlertService.cs @@ -0,0 +1,164 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Alerts; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IAlertService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IAlertService WithOptions(Func modifier); + + /// + /// This endpoint retrieves an alert by its ID. + /// + Task Retrieve( + AlertRetrieveParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Retrieve( + string alertID, + AlertRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint updates the thresholds of an alert. + /// + Task Update(AlertUpdateParams parameters, CancellationToken cancellationToken = default); + + /// + Task Update( + string alertConfigurationID, + AlertUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of alerts within Orb. + /// + /// The request must specify one of `customer_id`, `external_customer_id`, + /// or `subscription_id`. + /// + /// If querying by subscription_id, the endpoint will return the subscription + /// level alerts as well as the plan level alerts associated with the subscription. + /// + /// The list of alerts is ordered starting from the most recently created + /// alert. This endpoint follows Orb's [standardized pagination format](/api-reference/pagination). + /// + Task List( + AlertListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint creates a new alert to monitor a customer's credit balance. + /// There are three types of alerts that can be scoped to customers: `credit_balance_depleted`, + /// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have + /// a maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). + /// `credit_balance_dropped` alerts require a list of thresholds to be provided + /// while `credit_balance_depleted` and `credit_balance_recovered` alerts do + /// not require thresholds. + /// + Task CreateForCustomer( + AlertCreateForCustomerParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreateForCustomer( + string customerID, + AlertCreateForCustomerParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint creates a new alert to monitor a customer's credit balance. + /// There are three types of alerts that can be scoped to customers: `credit_balance_depleted`, + /// `credit_balance_dropped`, and `credit_balance_recovered`. Customers can have + /// a maximum of one of each type of alert per [credit balance currency](/product-catalog/prepurchase). + /// `credit_balance_dropped` alerts require a list of thresholds to be provided + /// while `credit_balance_depleted` and `credit_balance_recovered` alerts do + /// not require thresholds. + /// + Task CreateForExternalCustomer( + AlertCreateForExternalCustomerParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreateForExternalCustomer( + string externalCustomerID, + AlertCreateForExternalCustomerParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to create alerts at the subscription level. + /// + /// Subscription level alerts can be one of two types: `usage_exceeded` + /// or `cost_exceeded`. A `usage_exceeded` alert is scoped to a particular metric + /// and is triggered when the usage of that metric exceeds predefined thresholds + /// during the current billing cycle. A `cost_exceeded` alert is triggered when + /// the total amount due during the current billing cycle surpasses predefined + /// thresholds. `cost_exceeded` alerts do not include burndown of pre-purchase + /// credits. Each subscription can have one `cost_exceeded` alert and one `usage_exceeded` + /// alert per metric that is a part of the subscription. Alerts are triggered + /// based on usage or cost conditions met during the current billing cycle. + /// + Task CreateForSubscription( + AlertCreateForSubscriptionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreateForSubscription( + string subscriptionID, + AlertCreateForSubscriptionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to disable an alert. To disable a plan-level alert + /// for a specific subscription, you must include the `subscription_id`. The `subscription_id` + /// is not required for customer or subscription level alerts. + /// + Task Disable( + AlertDisableParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Disable( + string alertConfigurationID, + AlertDisableParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to enable an alert. To enable a plan-level alert + /// for a specific subscription, you must include the `subscription_id`. The `subscription_id` + /// is not required for customer or subscription level alerts. + /// + Task Enable(AlertEnableParams parameters, CancellationToken cancellationToken = default); + + /// + Task Enable( + string alertConfigurationID, + AlertEnableParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IBetaService.cs b/src/Orb/Services/IBetaService.cs new file mode 100644 index 00000000..5bf0fd52 --- /dev/null +++ b/src/Orb/Services/IBetaService.cs @@ -0,0 +1,72 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Beta; +using Orb.Models.Plans; +using Orb.Services.Beta; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IBetaService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IBetaService WithOptions(Func modifier); + + IExternalPlanIDService ExternalPlanID { get; } + + /// + /// This endpoint allows the creation of a new plan version for an existing plan. + /// + Task CreatePlanVersion( + BetaCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task CreatePlanVersion( + string planID, + BetaCreatePlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a plan version. It returns the phases, prices, + /// and adjustments present on this version of the plan. + /// + Task FetchPlanVersion( + BetaFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task FetchPlanVersion( + string version, + BetaFetchPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows setting the default version of a plan. + /// + Task SetDefaultPlanVersion( + BetaSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task SetDefaultPlanVersion( + string planID, + BetaSetDefaultPlanVersionParams parameters, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/ICouponService.cs b/src/Orb/Services/ICouponService.cs new file mode 100644 index 00000000..f2f1ff7f --- /dev/null +++ b/src/Orb/Services/ICouponService.cs @@ -0,0 +1,77 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Coupons; +using Coupons = Orb.Services.Coupons; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ICouponService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ICouponService WithOptions(Func modifier); + + Coupons::ISubscriptionService Subscriptions { get; } + + /// + /// This endpoint allows the creation of coupons, which can then be redeemed + /// at subscription creation or plan change. + /// + Task Create( + CouponCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all coupons for an account in a list format. + /// + /// The list of coupons is ordered starting from the most recently created + /// coupon. The response also includes `pagination_metadata`, which lets the caller + /// retrieve the next page of results if they exist. More information about pagination + /// can be found in the Pagination-metadata schema. + /// + Task List( + CouponListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows a coupon to be archived. Archived coupons can no longer + /// be redeemed, and will be hidden from lists of active coupons. Additionally, + /// once a coupon is archived, its redemption code can be reused for a different coupon. + /// + Task Archive( + CouponArchiveParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Archive( + string couponID, + CouponArchiveParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint retrieves a coupon by its ID. To fetch coupons by their redemption + /// code, use the [List coupons](list-coupons) endpoint with the redemption_code parameter. + /// + Task Fetch(CouponFetchParams parameters, CancellationToken cancellationToken = default); + + /// + Task Fetch( + string couponID, + CouponFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/ICreditNoteService.cs b/src/Orb/Services/ICreditNoteService.cs new file mode 100644 index 00000000..20d4fc93 --- /dev/null +++ b/src/Orb/Services/ICreditNoteService.cs @@ -0,0 +1,81 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models; +using Orb.Models.CreditNotes; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ICreditNoteService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ICreditNoteService WithOptions(Func modifier); + + /// + /// This endpoint is used to create a single [`Credit Note`](/invoicing/credit-notes). + /// + /// The credit note service period configuration supports two explicit modes: + /// + /// 1. Global service periods: Specify start_date and end_date at the credit + /// note level. These dates will be applied to all line items uniformly. + /// + /// 2. Individual service periods: Specify start_date and end_date for each + /// line item. When using this mode, ALL line items must have individual periods specified. + /// + /// 3. Default behavior: If no service periods are specified (neither global + /// nor individual), the original invoice line item service periods will be used. + /// + /// Note: Mixing global and individual service periods in the same request + /// is not allowed to prevent confusion. + /// + /// Service period dates are normalized to the start of the day in the customer's + /// timezone to ensure consistent handling across different timezones. + /// + /// Date Format: Use start_date and end_date with format "YYYY-MM-DD" (e.g., + /// "2023-09-22") to match other Orb APIs like /v1/invoice_line_items. + /// + /// Note: Both start_date and end_date are inclusive - the service period + /// will cover both the start date and end date completely (from start of start_date + /// to end of end_date). + /// + Task Create( + CreditNoteCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// Get a paginated list of CreditNotes. Users can also filter by customer_id, + /// subscription_id, or external_customer_id. The credit notes will be returned + /// in reverse chronological order by `creation_time`. + /// + Task List( + CreditNoteListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a single [`Credit Note`](/invoicing/credit-notes) + /// given an identifier. + /// + Task Fetch( + CreditNoteFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string creditNoteID, + CreditNoteFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/ICustomerService.cs b/src/Orb/Services/ICustomerService.cs new file mode 100644 index 00000000..f2fb2c60 --- /dev/null +++ b/src/Orb/Services/ICustomerService.cs @@ -0,0 +1,196 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Customers; +using Orb.Services.Customers; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ICustomerService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ICustomerService WithOptions(Func modifier); + + ICostService Costs { get; } + + ICreditService Credits { get; } + + IBalanceTransactionService BalanceTransactions { get; } + + /// + /// This operation is used to create an Orb customer, who is party to the core + /// billing relationship. See [Customer](/core-concepts##customer) for an overview + /// of the customer resource. + /// + /// This endpoint is critical in the following Orb functionality: * Automated + /// charges can be configured by setting `payment_provider` and `payment_provider_id` + /// to automatically issue invoices * [Customer ID Aliases](/events-and-metrics/customer-aliases) + /// can be configured by setting `external_customer_id` * [Timezone localization](/essentials/timezones) + /// can be configured on a per-customer basis by setting the `timezone` parameter + /// + Task Create( + CustomerCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to update the `payment_provider`, `payment_provider_id`, + /// `name`, `email`, `email_delivery`, `tax_id`, `auto_collection`, `metadata`, + /// `shipping_address`, `billing_address`, and `additional_emails` of an existing + /// customer. Other fields on a customer are currently immutable. + /// + Task Update( + CustomerUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string customerID, + CustomerUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all customers for an account. The list of + /// customers is ordered starting from the most recently created customer. This + /// endpoint follows Orb's [standardized pagination format](/api-reference/pagination). + /// + /// See [Customer](/core-concepts##customer) for an overview of the customer model. + /// + Task List( + CustomerListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This performs a deletion of this customer, its subscriptions, and its invoices, + /// provided the customer does not have any issued invoices. Customers with issued + /// invoices cannot be deleted. This operation is irreversible. Note that this + /// is a _soft_ deletion, but the data will be inaccessible through the API and + /// Orb dashboard. + /// + /// For a hard-deletion, please reach out to the Orb team directly. + /// + /// **Note**: This operation happens asynchronously and can be expected + /// to take a few minutes to propagate to related resources. However, querying + /// for the customer on subsequent GET requests while deletion is in process will + /// reflect its deletion. + /// + Task Delete(CustomerDeleteParams parameters, CancellationToken cancellationToken = default); + + /// + Task Delete( + string customerID, + CustomerDeleteParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch customer details given an identifier. If the + /// `Customer` is in the process of being deleted, only the properties `id` and + /// `deleted: true` will be returned. + /// + /// See the [Customer resource](/core-concepts#customer) for a full discussion + /// of the Customer model. + /// + Task Fetch( + CustomerFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string customerID, + CustomerFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch customer details given an `external_customer_id` + /// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). + /// + /// Note that the resource and semantics of this endpoint exactly mirror + /// [Get Customer](fetch-customer). + /// + Task FetchByExternalID( + CustomerFetchByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task FetchByExternalID( + string externalCustomerID, + CustomerFetchByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Sync Orb's payment methods for the customer with their gateway. + /// + /// This method can be called before taking an action that may cause the + /// customer to be charged, ensuring that the most up-to-date payment method + /// is charged. + /// + /// **Note**: This functionality is currently only available for Stripe. + /// + Task SyncPaymentMethodsFromGateway( + CustomerSyncPaymentMethodsFromGatewayParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task SyncPaymentMethodsFromGateway( + string customerID, + CustomerSyncPaymentMethodsFromGatewayParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Sync Orb's payment methods for the customer with their gateway. + /// + /// This method can be called before taking an action that may cause the + /// customer to be charged, ensuring that the most up-to-date payment method + /// is charged. + /// + /// **Note**: This functionality is currently only available for Stripe. + /// + Task SyncPaymentMethodsFromGatewayByExternalCustomerID( + CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task SyncPaymentMethodsFromGatewayByExternalCustomerID( + string externalCustomerID, + CustomerSyncPaymentMethodsFromGatewayByExternalCustomerIDParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to update customer details given an `external_customer_id` + /// (see [Customer ID Aliases](/events-and-metrics/customer-aliases)). Note that + /// the resource and semantics of this endpoint exactly mirror [Update Customer](update-customer). + /// + Task UpdateByExternalID( + CustomerUpdateByExternalIDParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task UpdateByExternalID( + string id, + CustomerUpdateByExternalIDParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IDimensionalPriceGroupService.cs b/src/Orb/Services/IDimensionalPriceGroupService.cs new file mode 100644 index 00000000..7fde7261 --- /dev/null +++ b/src/Orb/Services/IDimensionalPriceGroupService.cs @@ -0,0 +1,81 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.DimensionalPriceGroups; +using Orb.Services.DimensionalPriceGroups; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IDimensionalPriceGroupService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IDimensionalPriceGroupService WithOptions(Func modifier); + + IExternalDimensionalPriceGroupIDService ExternalDimensionalPriceGroupID { get; } + + /// + /// A dimensional price group is used to partition the result of a billable metric + /// by a set of dimensions. Prices in a price group must specify the partition + /// used to derive their usage. + /// + /// For example, suppose we have a billable metric that measures the number + /// of widgets used and we want to charge differently depending on the color of + /// the widget. We can create a price group with a dimension "color" and two + /// prices: one that charges \$10 per red widget and one that charges \$20 per + /// blue widget. + /// + Task Create( + DimensionalPriceGroupCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// Fetch dimensional price group + /// + Task Retrieve( + DimensionalPriceGroupRetrieveParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Retrieve( + string dimensionalPriceGroupID, + DimensionalPriceGroupRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to update the `external_dimensional_price_group_id` + /// and `metadata` of an existing dimensional price group. Other fields on a dimensional + /// price group are currently immutable. + /// + Task Update( + DimensionalPriceGroupUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string dimensionalPriceGroupID, + DimensionalPriceGroupUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// List dimensional price groups + /// + Task List( + DimensionalPriceGroupListParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IEventService.cs b/src/Orb/Services/IEventService.cs new file mode 100644 index 00000000..7daba2f3 --- /dev/null +++ b/src/Orb/Services/IEventService.cs @@ -0,0 +1,329 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Events; +using Orb.Services.Events; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IEventService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IEventService WithOptions(Func modifier); + + IBackfillService Backfills { get; } + + IVolumeService Volume { get; } + + /// + /// This endpoint is used to amend a single usage event with a given `event_id`. + /// `event_id` refers to the `idempotency_key` passed in during ingestion. The + /// event will maintain its existing `event_id` after the amendment. + /// + /// This endpoint will mark the existing event as ignored, and Orb will + /// only use the new event passed in the body of this request as the source of + /// truth for that `event_id`. Note that a single event can be amended any number + /// of times, so the same event can be overwritten in subsequent calls to this + /// endpoint. Only a single event with a given `event_id` will be considered + /// the source of truth at any given time. + /// + /// This is a powerful and audit-safe mechanism to retroactively update + /// a single event in cases where you need to: * update an event with new metadata + /// as you iterate on your pricing model * update an event based on the result + /// of an external API call (e.g. call to a payment gateway succeeded or failed) + /// + /// This amendment API is always audit-safe. The process will still retain + /// the original event, though it will be ignored for billing calculations. For + /// auditing and data fidelity purposes, Orb never overwrites or permanently deletes + /// ingested usage data. + /// + /// ## Request validation * The `timestamp` of the new event must match + /// the `timestamp` of the existing event already ingested. As with ingestion, + /// all timestamps must be sent in ISO8601 format with UTC timezone offset. * + /// The `customer_id` or `external_customer_id` of the new event must match the + /// `customer_id` or `external_customer_id` of the existing event already ingested. + /// Exactly one of `customer_id` and `external_customer_id` should be specified, + /// and similar to ingestion, the ID must identify a Customer resource within + /// Orb. Unlike ingestion, for event amendment, we strictly enforce that the + /// Customer must be in the Orb system, even during the initial integration + /// period. We do not allow updating the `Customer` an event is associated + /// with. * Orb does not accept an `idempotency_key` with the event in this endpoint, + /// since this request is by design idempotent. On retryable errors, you should + /// retry the request and assume the amendment operation has not succeeded until + /// receipt of a 2xx. * The event's `timestamp` must fall within the customer's + /// current subscription's billing period, or within the grace period of the + /// customer's current subscription's previous billing period. * By default, no + /// more than 100 events can be amended for a single customer in a 100 day period. + /// For higher volume updates, consider using the [event backfill](create-backfill) endpoint. + /// + Task Update( + EventUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string eventID, + EventUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to deprecate a single usage event with a given `event_id`. + /// `event_id` refers to the `idempotency_key` passed in during ingestion. + /// + /// This endpoint will mark the existing event as ignored. Note that if + /// you attempt to re-ingest an event with the same `event_id` as a deprecated + /// event, Orb will return an error. + /// + /// This is a powerful and audit-safe mechanism to retroactively deprecate + /// a single event in cases where you need to: * no longer bill for an event + /// that was improperly reported * no longer bill for an event based on the result + /// of an external API call (e.g. call to a payment gateway failed and the user + /// should not be billed) + /// + /// If you want to only change specific properties of an event, but keep + /// the event as part of the billing calculation, use the [Amend event](amend-event) + /// endpoint instead. + /// + /// This API is always audit-safe. The process will still retain the deprecated + /// event, though it will be ignored for billing calculations. For auditing and + /// data fidelity purposes, Orb never overwrites or permanently deletes ingested + /// usage data. + /// + /// ## Request validation * Orb does not accept an `idempotency_key` with + /// the event in this endpoint, since this request is by design idempotent. + /// On retryable errors, you should retry the request and assume the deprecation + /// operation has not succeeded until receipt of a 2xx. * The event's `timestamp` + /// must fall within the customer's current subscription's billing period, or + /// within the grace period of the customer's current subscription's previous + /// billing period. Orb does not allow deprecating events for billing periods + /// that have already invoiced customers. * The `customer_id` or the `external_customer_id` + /// of the original event ingestion request must identify a Customer resource + /// within Orb, even if this event was ingested during the initial integration + /// period. We do not allow deprecating events for customers not in the Orb + /// system. * By default, no more than 100 events can be deprecated for a single + /// customer in a 100 day period. For higher volume updates, consider using + /// the [event backfill](create-backfill) endpoint. + /// + Task Deprecate( + EventDeprecateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Deprecate( + string eventID, + EventDeprecateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Orb's event ingestion model and API is designed around two core principles: + /// + /// 1. **Data fidelity**: The accuracy of your billing model depends on + /// a robust foundation of events. Orb's API protocol encourages usage patterns + /// that ensure that your data is consistently complete and correct. 2. **Fast + /// integration**: Sending events into Orb requires no tedious setup steps or + /// explicit field schema for your event shape, making it instant to start streaming + /// in usage in real-time. + /// + /// ## Event shape + /// + /// Events are the starting point for all usage calculations in the system, + /// and are simple at their core: + /// + /// ```ts { // customer_id and external_customer_id are used to // + /// attribute usage to a given Customer. Exactly one of these // should be specified + /// in a given ingestion event. + /// + /// // `customer_id` is the Orb generated identifier for the Customer, + /// // which is returned from the Create customer API call. customer_id: string, + /// + /// // external_customer_id is an alternate identifier which is associated + /// // with a Customer at creation time. This is treated as an alias for // + /// customer_id, and is usually set to an identifier native to your system. + /// external_customer_id: string, + /// + /// // A string name identifying the event, usually a usage // action. + /// By convention, this should not contain any whitespace. event_name: string, + /// + /// // An ISO 8601 format date with no timezone offset. // This should + /// represent the time that usage occurred // and is important to attribute + /// usage to a given // billing period. See the notes below on determining + /// the timestamp. // e.g. 2020-12-09T16:09:53Z timestamp: string, + /// + /// // A unique value, generated by the client, that is // used to de-duplicate + /// events. // Exactly one event with a given // idempotency key will be ingested, + /// which allows for // safe request retries. idempotency_key: string + /// + /// // Optional custom metadata to attach to the event. // This might + /// include a numeric value used for aggregation, // or a string/boolean value + /// used for filtering. // The schema of this dictionary need not be pre-declared, + /// and // properties can be added at any time. properties: { [key: string]?: + /// string | number | boolean, }, } ``` + /// + /// ## Required fields Because events streamed to Orb are meant to be as + /// flexible as possible, there are only a few required fields in every event. + /// + /// - We recommend that `idempotency_key` are unique strings that you generated + /// with V4 UUIDs, but only require that they uniquely identify an event (i.e. + /// don’t collide). - The `timestamp` field in the event body will be used to + /// determine which billable period a given event falls into. For example, with + /// a monthly billing cycle starting from the first of December, Orb will calculate + /// metrics based on events that fall into the range `12-01 00:00:00 <= timestamp + /// < 01-01 00:00:00`. + /// + /// ## Logging metadata + /// + /// Orb allows tagging events with metadata using a flexible properties + /// dictionary. Since Orb does not enforce a rigid schema for this field-set, + /// key-value pairs can be added dynamically as your events evolve. + /// + /// This dictionary can be helpful for a wide variety of use cases: + /// + /// - Numeric properties on events like `compute_time_ms` can later be + /// inputs to our flexible query engine to determine usage. - Logging a region + /// or cluster with each event can help you provide customers more granular visibility + /// into their usage. - If you are using matrix pricing and matching a matrix + /// price key with a property, you should ensure the value for that property is + /// sent as a string. + /// + /// We encourage logging this metadata with an eye towards future use cases + /// to ensure full coverage for historical data. The datatype of the value in + /// the properties dictionary is important for metric creation from an event + /// source. Values that you wish to numerically aggregate should be of numeric + /// type in the event. + /// + /// ## Determining event timestamp For cases where usage is being reported + /// in real time as it is occurring, timestamp should correspond to the time + /// that usage occurred. + /// + /// In cases where usage is reported in aggregate for a historical timeframe + /// at a regular interval, we recommend setting the event `timestamp` to the + /// midpoint of the interval. As an example, if you have an hourly reporter that + /// sends data once an hour for the previous hour of usage, setting the `timestamp` + /// to the half-hour mark will ensure that the usage is counted within the correct period. + /// + /// Note that other time-related fields (e.g. time elapsed) can be added + /// to the properties dictionary as necessary. + /// + /// In cases where usage is reported in aggregate for a historical timeframe, + /// the timestamp must be within the grace period set for your account. Events + /// with `timestamp < current_time - grace_period` will not be accepted as a valid + /// event, and will throw validation errors. Enforcing the grace period enables + /// Orb to accurately map usage to the correct billing cycle and ensure that + /// all usage is billed for in the corresponding billing period. + /// + /// In general, Orb does not expect events with future dated timestamps. + /// In cases where the timestamp is at least 24 hours ahead of the current time, + /// the event will not be accepted as a valid event, and will throw validation errors. + /// + /// ## Event validation + /// + /// Orb’s validation ensures that you recognize errors in your events as + /// quickly as possible, and the API provides informative error messages to help + /// you fix problems quickly. + /// + /// We validate the following: + /// + /// - Exactly one of `customer_id` and `external_customer_id` should be + /// specified. - If the `customer_id` is specified, the customer in Orb must exist. + /// - If the `external_customer_id` is specified, the customer in Orb does not + /// need to exist. Events will be attributed to any future customers with the + /// `external_customer_id` on subscription creation. - `timestamp` must conform + /// to ISO 8601 and represent a timestamp at most 1 hour in the future. This + /// timestamp should be sent in UTC timezone (no timezone offset). + /// + /// ## Idempotency and retry semantics + /// + /// Orb's idempotency guarantees allow you to implement safe retry logic + /// in the event of network or machine failures, ensuring data fidelity. Each + /// event in the request payload is associated with an idempotency key, and Orb + /// guarantees that a single idempotency key will be successfully ingested at + /// most once. Note that when Orb encounters events with duplicate idempotency + /// keys and differing event bodies in a batch of events, the entire batch will + /// be rejected. + /// + /// - Successful responses return a 200 HTTP status code. The response contains + /// information about previously processed events. - Requests that return a `4xx` + /// HTTP status code indicate a payload error and contain at least one event + /// with a validation failure. An event with a validation failure can be re-sent + /// to the ingestion endpoint (after the payload is fixed) with the original idempotency + /// key since that key is not marked as processed. - Requests that return a `5xx` + /// HTTP status code indicate a server-side failure. These requests should be + /// retried in their entirety. + /// + /// ## API usage and limits The ingestion API is designed made for real-time + /// streaming ingestion and architected for high throughput. Even if events are + /// later deemed unnecessary or filtered out, we encourage you to log them to + /// Orb if they may be relevant to billing calculations in the future. + /// + /// To take advantage of the real-time features of the Orb platform and + /// avoid any chance of dropped events by producers, we recommend reporting events + /// to Orb frequently. Optionally, events can also be briefly aggregated at the + /// source, as this API accepts an array of event bodies. + /// + /// Orb does not currently enforce a hard rate-limit for API usage or a + /// maximum request payload size, but please give us a heads up if you’re changing + /// either of these factors by an order of magnitude from initial setup. + /// + /// ## Testing in debug mode The ingestion API supports a debug mode, which + /// returns additional verbose output to indicate which event idempotency keys + /// were newly ingested or duplicates from previous requests. To enable this + /// mode, mark `debug=true` as a query parameter. + /// + /// If `debug=true` is not specified, the response will only contain `validation_failed`. + /// Orb will still honor the idempotency guarantees set [here](/events-and-metrics/event-ingestion#event-volume-and-concurrency) + /// in all cases. + /// + /// We strongly recommend that you only use debug mode as part of testing + /// your initial Orb integration. Once you're ready to switch to production, + /// disable debug mode to take advantage of improved performance and maximal throughput. + /// + /// #### Example: ingestion response with `debug=true` + /// + /// ```json { "debug": { "duplicate": [], "ingested": [ + /// "B7E83HDMfJPAunXW", "SJs5DQJ3TnwSqEZE", "8SivfDsNKwCeAXim" + /// ] }, "validation_failed": [] } ``` + /// + /// #### Example: ingestion response with `debug=false` + /// + /// ```json { "validation_failed": [] } ``` + /// + Task Ingest( + EventIngestParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a filtered set of events for an account in a [paginated + /// list format](/api-reference/pagination). + /// + /// Note that this is a `POST` endpoint rather than a `GET` endpoint because + /// it employs a JSON body for search criteria rather than query parameters, allowing + /// for a more flexible search syntax. + /// + /// Note that a search criteria _must_ be specified. Currently, Orb supports + /// the following criteria: - `event_ids`: This is an explicit array of IDs to + /// filter by. Note that an event's ID is the `idempotency_key` that was originally + /// used for ingestion. + /// + /// By default, Orb will not throw a `404` if no events matched, Orb will + /// return an empty array for `data` instead. + /// + Task Search( + EventSearchParams parameters, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IInvoiceLineItemService.cs b/src/Orb/Services/IInvoiceLineItemService.cs new file mode 100644 index 00000000..2eb2c748 --- /dev/null +++ b/src/Orb/Services/IInvoiceLineItemService.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.InvoiceLineItems; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IInvoiceLineItemService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IInvoiceLineItemService WithOptions(Func modifier); + + /// + /// This creates a one-off fixed fee invoice line item on an Invoice. This can + /// only be done for invoices that are in a `draft` status. + /// + /// The behavior depends on which parameters are provided: - If `item_id` + /// is provided without `name`: The item is looked up by ID, and the item's name + /// is used for the line item. - If `name` is provided without `item_id`: An + /// item with the given name is searched for in the account. If found, that + /// item is used. If not found, a new item is created with that name. The new + /// item's name is used for the line item. - If both `item_id` and `name` are + /// provided: The item is looked up by ID for association, but the provided + /// `name` is used for the line item (not the item's name). + /// + Task Create( + InvoiceLineItemCreateParams parameters, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IInvoiceService.cs b/src/Orb/Services/IInvoiceService.cs new file mode 100644 index 00000000..8aa19068 --- /dev/null +++ b/src/Orb/Services/IInvoiceService.cs @@ -0,0 +1,167 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models; +using Orb.Models.Invoices; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IInvoiceService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IInvoiceService WithOptions(Func modifier); + + /// + /// This endpoint is used to create a one-off invoice for a customer. + /// + Task Create( + InvoiceCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to update the `metadata`, `net_terms`, `due_date`, + /// and `invoice_date` properties on an invoice. If you pass null for the metadata + /// value, it will clear any existing metadata for that invoice. + /// + /// `metadata` can be modified regardless of invoice state. `net_terms`, + /// `due_date`, and `invoice_date` can only be modified if the invoice is in a + /// `draft` state. `invoice_date` can only be modified for non-subscription invoices. + /// + Task Update( + InvoiceUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string invoiceID, + InvoiceUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all [`Invoice`](/core-concepts#invoice)s + /// for an account in a list format. + /// + /// The list of invoices is ordered starting from the most recently issued + /// invoice date. The response also includes [`pagination_metadata`](/api-reference/pagination), + /// which lets the caller retrieve the next page of results if they exist. + /// + /// By default, this only returns invoices that are `issued`, `paid`, or `synced`. + /// + /// When fetching any `draft` invoices, this returns the last-computed invoice + /// values for each draft invoice, which may not always be up-to-date since Orb + /// regularly refreshes invoices asynchronously. + /// + Task List( + InvoiceListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch an [`Invoice`](/core-concepts#invoice) given + /// an identifier. + /// + Task Fetch( + InvoiceFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string invoiceID, + InvoiceFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to fetch the upcoming [invoice](/core-concepts#invoice) + /// for the current billing period given a subscription. + /// + Task FetchUpcoming( + InvoiceFetchUpcomingParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows an eligible invoice to be issued manually. This is only + /// possible with invoices where status is `draft`, `will_auto_issue` is false, + /// and an `eligible_to_issue_at` is a time in the past. Issuing an invoice could + /// possibly trigger side effects, some of which could be customer-visible (e.g. + /// sending emails, auto-collecting payment, syncing the invoice to external + /// providers, etc). + /// + Task Issue( + InvoiceIssueParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Issue( + string invoiceID, + InvoiceIssueParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows an invoice's status to be set to the `paid` status. This + /// can only be done to invoices that are in the `issued` or `synced` status. + /// + Task MarkPaid( + InvoiceMarkPaidParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task MarkPaid( + string invoiceID, + InvoiceMarkPaidParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint collects payment for an invoice using the customer's default + /// payment method. This action can only be taken on invoices with status "issued". + /// + Task Pay(InvoicePayParams parameters, CancellationToken cancellationToken = default); + + /// + Task Pay( + string invoiceID, + InvoicePayParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows an invoice's status to be set to the `void` status. This + /// can only be done to invoices that are in the `issued` status. + /// + /// If the associated invoice has used the customer balance to change the + /// amount due, the customer balance operation will be reverted. For example, + /// if the invoice used \$10 of customer balance, that amount will be added back + /// to the customer balance upon voiding. + /// + /// If the invoice was used to purchase a credit block, but the invoice + /// is not yet paid, the credit block will be voided. If the invoice was created + /// due to a top-up, the top-up will be disabled. + /// + Task Void(InvoiceVoidParams parameters, CancellationToken cancellationToken = default); + + /// + Task Void( + string invoiceID, + InvoiceVoidParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IItemService.cs b/src/Orb/Services/IItemService.cs new file mode 100644 index 00000000..fed6194a --- /dev/null +++ b/src/Orb/Services/IItemService.cs @@ -0,0 +1,72 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Items; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IItemService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IItemService WithOptions(Func modifier); + + /// + /// This endpoint is used to create an [Item](/core-concepts#item). + /// + Task Create(ItemCreateParams parameters, CancellationToken cancellationToken = default); + + /// + /// This endpoint can be used to update properties on the Item. + /// + Task Update(ItemUpdateParams parameters, CancellationToken cancellationToken = default); + + /// + Task Update( + string itemID, + ItemUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all Items, ordered in descending order by + /// creation time. + /// + Task List( + ItemListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Archive item + /// + Task Archive(ItemArchiveParams parameters, CancellationToken cancellationToken = default); + + /// + Task Archive( + string itemID, + ItemArchiveParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns an item identified by its item_id. + /// + Task Fetch(ItemFetchParams parameters, CancellationToken cancellationToken = default); + + /// + Task Fetch( + string itemID, + ItemFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IMetricService.cs b/src/Orb/Services/IMetricService.cs new file mode 100644 index 00000000..06731507 --- /dev/null +++ b/src/Orb/Services/IMetricService.cs @@ -0,0 +1,75 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Metrics; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IMetricService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IMetricService WithOptions(Func modifier); + + /// + /// This endpoint is used to create a [metric](/core-concepts###metric) using + /// a SQL string. See [SQL support](/extensibility/advanced-metrics#sql-support) + /// for a description of constructing SQL queries with examples. + /// + Task Create( + MetricCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to update the `metadata` property on a metric. If + /// you pass `null` for the metadata value, it will clear any existing metadata + /// for that invoice. + /// + Task Update( + MetricUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string metricID, + MetricUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch [metric](/core-concepts##metric) details given + /// a metric identifier. It returns information about the metrics including its + /// name, description, and item. + /// + Task List( + MetricListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to list [metrics](/core-concepts#metric). It returns + /// information about the metrics including its name, description, and item. + /// + Task Fetch( + MetricFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string metricID, + MetricFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IPlanService.cs b/src/Orb/Services/IPlanService.cs new file mode 100644 index 00000000..b9b6f7c2 --- /dev/null +++ b/src/Orb/Services/IPlanService.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Plans; +using Orb.Services.Plans; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IPlanService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IPlanService WithOptions(Func modifier); + + IExternalPlanIDService ExternalPlanID { get; } + + /// + /// This endpoint allows creation of plans including their prices. + /// + Task Create(PlanCreateParams parameters, CancellationToken cancellationToken = default); + + /// + /// This endpoint can be used to update the `external_plan_id`, and `metadata` + /// of an existing plan. + /// + /// Other fields on a plan are currently immutable. + /// + Task Update(PlanUpdateParams parameters, CancellationToken cancellationToken = default); + + /// + Task Update( + string planID, + PlanUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all [plans](/core-concepts#plan-and-price) + /// for an account in a list format. The list of plans is ordered starting from + /// the most recently created plan. The response also includes [`pagination_metadata`](/api-reference/pagination), + /// which lets the caller retrieve the next page of results if they exist. + /// + Task List( + PlanListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch [plan](/core-concepts#plan-and-price) details + /// given a plan identifier. It returns information about the prices included + /// in the plan and their configuration, as well as the product that the plan + /// is attached to. + /// + /// ## Serialized prices Orb supports a few different pricing models out + /// of the box. Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) + /// object. The `model_type` field determines the key for the configuration object + /// that is present. A detailed explanation of price types can be found in the + /// [Price schema](/core-concepts#plan-and-price). + /// + /// ## Phases Orb supports plan phases, also known as contract ramps. For + /// plans with phases, the serialized prices refer to all prices across all phases. + /// + Task Fetch(PlanFetchParams parameters, CancellationToken cancellationToken = default); + + /// + Task Fetch( + string planID, + PlanFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/IPriceService.cs b/src/Orb/Services/IPriceService.cs new file mode 100644 index 00000000..63f811a3 --- /dev/null +++ b/src/Orb/Services/IPriceService.cs @@ -0,0 +1,177 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Prices; +using Orb.Services.Prices; +using Models = Orb.Models; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IPriceService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IPriceService WithOptions(Func modifier); + + IExternalPriceIDService ExternalPriceID { get; } + + /// + /// This endpoint is used to create a [price](/product-catalog/price-configuration). + /// A price created using this endpoint is always an add-on, meaning that it's + /// not associated with a specific plan and can instead be individually added + /// to subscriptions, including subscriptions on different plans. + /// + /// An `external_price_id` can be optionally specified as an alias to allow + /// ergonomic interaction with prices in the Orb API. + /// + /// See the [Price resource](/product-catalog/price-configuration) for the + /// specification of different price model configurations possible in this endpoint. + /// + Task Create( + PriceCreateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint allows you to update the `metadata` property on a price. If + /// you pass null for the metadata value, it will clear any existing metadata + /// for that price. + /// + Task Update( + PriceUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string priceID, + PriceUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to list all add-on prices created using the [price creation endpoint](/api-reference/price/create-price). + /// + Task List( + PriceListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// [NOTE] It is recommended to use the `/v1/prices/evaluate` which offers further + /// functionality, such as multiple prices, inline price definitions, and querying + /// over preview events. + /// + /// This endpoint is used to evaluate the output of a price for a given + /// customer and time range. It enables filtering and grouping the output using + /// [computed properties](/extensibility/advanced-metrics#computed-properties), + /// supporting the following workflows: + /// + /// 1. Showing detailed usage and costs to the end customer. 2. Auditing + /// subtotals on invoice line items. + /// + /// For these workflows, the expressiveness of computed properties in both + /// the filters and grouping is critical. For example, if you'd like to show your + /// customer their usage grouped by hour and another property, you can do so with + /// the following `grouping_keys`: `["hour_floor_timestamp_millis(timestamp_millis)", + /// "my_property"]`. If you'd like to examine a customer's usage for a specific + /// property value, you can do so with the following `filter`: `my_property = + /// 'foo' AND my_other_property = 'bar'`. + /// + /// By default, the start of the time range must be no more than 100 days + /// ago and the length of the results must be no greater than 1000. Note that + /// this is a POST endpoint rather than a GET endpoint because it employs a JSON + /// body rather than query parameters. + /// + Task Evaluate( + PriceEvaluateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Evaluate( + string priceID, + PriceEvaluateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to evaluate the output of price(s) for a given customer + /// and time range over ingested events. It enables filtering and grouping the + /// output using [computed properties](/extensibility/advanced-metrics#computed-properties), + /// supporting the following workflows: + /// + /// 1. Showing detailed usage and costs to the end customer. 2. Auditing + /// subtotals on invoice line items. + /// + /// For these workflows, the expressiveness of computed properties in both + /// the filters and grouping is critical. For example, if you'd like to show your + /// customer their usage grouped by hour and another property, you can do so with + /// the following `grouping_keys`: `["hour_floor_timestamp_millis(timestamp_millis)", + /// "my_property"]`. If you'd like to examine a customer's usage for a specific + /// property value, you can do so with the following `filter`: `my_property = + /// 'foo' AND my_other_property = 'bar'`. + /// + /// Prices may either reference existing prices in your Orb account or be + /// defined inline in the request body. Up to 100 prices can be evaluated in + /// a single request. + /// + /// Prices are evaluated on ingested events and the start of the time range + /// must be no more than 100 days ago. To evaluate based off a set of provided + /// events, the [evaluate preview events](/api-reference/price/evaluate-preview-events) + /// endpoint can be used instead. + /// + /// Note that this is a POST endpoint rather than a GET endpoint because + /// it employs a JSON body rather than query parameters. + /// + Task EvaluateMultiple( + PriceEvaluateMultipleParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint evaluates prices on preview events instead of actual usage, + /// making it ideal for building price calculators and cost estimation tools. + /// You can filter and group results using [computed properties](/extensibility/advanced-metrics#computed-properties) + /// to analyze pricing across different dimensions. + /// + /// Prices may either reference existing prices in your Orb account or be + /// defined inline in the request body. The endpoint has the following limitations: + /// 1. Up to 100 prices can be evaluated in a single request. 2. Up to 500 preview + /// events can be provided in a single request. + /// + /// A top-level customer_id is required to evaluate the preview events. + /// Additionally, all events without a customer_id will have the top-level customer_id added. + /// + /// Note that this is a POST endpoint rather than a GET endpoint because + /// it employs a JSON body rather than query parameters. + /// + Task EvaluatePreviewEvents( + PriceEvaluatePreviewEventsParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a price given an identifier. + /// + Task Fetch( + PriceFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string priceID, + PriceFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/ISubscriptionChangeService.cs b/src/Orb/Services/ISubscriptionChangeService.cs new file mode 100644 index 00000000..90adca7b --- /dev/null +++ b/src/Orb/Services/ISubscriptionChangeService.cs @@ -0,0 +1,78 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.SubscriptionChanges; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ISubscriptionChangeService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ISubscriptionChangeService WithOptions(Func modifier); + + /// + /// This endpoint returns a subscription change given an identifier. + /// + /// A subscription change is created by including `Create-Pending-Subscription-Change: + /// True` in the header of a subscription mutation API call (e.g. [create subscription + /// endpoint](/api-reference/subscription/create-subscription), [schedule plan + /// change endpoint](/api-reference/subscription/schedule-plan-change), ...). + /// The subscription change will be referenced by the `pending_subscription_change` + /// field in the response. + /// + Task Retrieve( + SubscriptionChangeRetrieveParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Retrieve( + string subscriptionChangeID, + SubscriptionChangeRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Apply a subscription change to perform the intended action. If a positive + /// amount is passed with a request to this endpoint, any eligible invoices that + /// were created will be issued immediately if they only contain in-advance fees. + /// + Task Apply( + SubscriptionChangeApplyParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Apply( + string subscriptionChangeID, + SubscriptionChangeApplyParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Cancel a subscription change. The change can no longer be applied. A subscription + /// can only have one "pending" change at a time - use this endpoint to cancel + /// an existing change before creating a new one. + /// + Task Cancel( + SubscriptionChangeCancelParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Cancel( + string subscriptionChangeID, + SubscriptionChangeCancelParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/ISubscriptionService.cs b/src/Orb/Services/ISubscriptionService.cs new file mode 100644 index 00000000..6abd7b2d --- /dev/null +++ b/src/Orb/Services/ISubscriptionService.cs @@ -0,0 +1,931 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.SubscriptionChanges; +using Orb.Models.Subscriptions; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ISubscriptionService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ISubscriptionService WithOptions(Func modifier); + + /// + /// A subscription represents the purchase of a plan by a customer. The customer + /// is identified by either the `customer_id` or the `external_customer_id`, + /// and exactly one of these fields must be provided. + /// + /// By default, subscriptions begin on the day that they're created and + /// renew automatically for each billing cycle at the cadence that's configured + /// in the plan definition. + /// + /// The default configuration for subscriptions in Orb is **In-advance billing** + /// and **Beginning of month alignment** (see [Subscription](/core-concepts##subscription) + /// for more details). + /// + /// In order to change the alignment behavior, Orb also supports billing + /// subscriptions on the day of the month they are created. If `align_billing_with_subscription_start_date + /// = true` is specified, subscriptions have billing cycles that are aligned + /// with their `start_date`. For example, a subscription that begins on January + /// 15th will have a billing cycle from January 15th to February 15th. Every + /// subsequent billing cycle will continue to start and invoice on the 15th. + /// + /// If the "day" value is greater than the number of days in the month, + /// the next billing cycle will start at the end of the month. For example, if + /// the start_date is January 31st, the next billing cycle will start on February 28th. + /// + /// If a customer was created with a currency, Orb only allows subscribing + /// the customer to a plan with a matching `invoicing_currency`. If the customer + /// does not have a currency set, on subscription creation, we set the customer's + /// currency to be the `invoicing_currency` of the plan. + /// + /// ## Customize your customer's subscriptions + /// + /// Prices and adjustments in a plan can be added, removed, or replaced + /// for the subscription being created. This is useful when a customer has prices + /// that differ from the default prices for a specific plan. + /// + /// This feature is only available for accounts that have migrated + /// to Subscription Overrides Version 2. You can find your Subscription Overrides + /// Version at the bottom of your [Plans page](https://app.withorb.com/plans) + /// + /// ### Adding Prices + /// + /// To add prices, provide a list of objects with the key `add_prices`. + /// An object in the list must specify an existing add-on price with a `price_id` + /// or `external_price_id` field, or create a new add-on price by including an + /// object with the key `price`, identical to what would be used in the request + /// body for the [create price endpoint](/api-reference/price/create-price). + /// See the [Price resource](/product-catalog/price-configuration) for the specification + /// of different price model configurations possible in this object. + /// + /// If the plan has phases, each object in the list must include a number + /// with `plan_phase_order` key to indicate which phase the price should be added to. + /// + /// An object in the list can specify an optional `start_date` and optional + /// `end_date`. This is equivalent to creating a price interval with the [add/edit + /// price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). + /// If unspecified, the start or end date of the phase or subscription will be used. + /// + /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, + /// or `discounts`. This will create adjustments which apply only to this price. + /// + /// Additionally, an object in the list can specify an optional `reference_id`. + /// This ID can be used to reference this price when [adding an adjustment](#adding-adjustments) + /// in the same API call. However the ID is _transient_ and cannot be used to + /// refer to the price in future API calls. + /// + /// ### Removing Prices + /// + /// To remove prices, provide a list of objects with the key `remove_prices`. + /// An object in the list must specify a plan price with either a `price_id` + /// or `external_price_id` field. + /// + /// ### Replacing Prices + /// + /// To replace prices, provide a list of objects with the key `replace_prices`. + /// An object in the list must specify a plan price to replace with the `replaces_price_id` + /// key, and it must specify a price to replace it with by either referencing + /// an existing add-on price with a `price_id` or `external_price_id` field, or + /// by creating a new add-on price by including an object with the key `price`, + /// identical to what would be used in the request body for the [create price + /// endpoint](/api-reference/price/create-price). See the [Price resource](/product-catalog/price-configuration) + /// for the specification of different price model configurations possible in + /// this object. + /// + /// For fixed fees, an object in the list can supply a `fixed_price_quantity` + /// instead of a `price`, `price_id`, or `external_price_id` field. This will + /// update only the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. + /// + /// The replacement price will have the same phase, if applicable, and the + /// same start and end dates as the price it replaces. + /// + /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, + /// or `discounts`. This will create adjustments which apply only to this price. + /// + /// Additionally, an object in the list can specify an optional `reference_id`. + /// This ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) + /// in the same API call. However the ID is _transient_ and cannot be used to + /// refer to the price in future API calls. + /// + /// ### Adding adjustments + /// + /// To add adjustments, provide a list of objects with the key `add_adjustments`. + /// An object in the list must include an object with the key `adjustment`, identical + /// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). + /// + /// If the plan has phases, each object in the list must include a number + /// with `plan_phase_order` key to indicate which phase the adjustment should + /// be added to. + /// + /// An object in the list can specify an optional `start_date` and optional + /// `end_date`. If unspecified, the start or end date of the phase or subscription + /// will be used. + /// + /// ### Removing adjustments + /// + /// To remove adjustments, provide a list of objects with the key `remove_adjustments`. + /// An object in the list must include a key, `adjustment_id`, with the ID of + /// the adjustment to be removed. + /// + /// ### Replacing adjustments + /// + /// To replace adjustments, provide a list of objects with the key `replace_adjustments`. + /// An object in the list must specify a plan adjustment to replace with the + /// `replaces_adjustment_id` key, and it must specify an adjustment to replace + /// it with by including an object with the key `adjustment`, identical to the + /// adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). + /// + /// The replacement adjustment will have the same phase, if applicable, + /// and the same start and end dates as the adjustment it replaces. + /// + /// ## Price overrides (DEPRECATED) + /// + /// Price overrides are being phased out in favor adding/removing/replacing + /// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/create-subscription)) + /// + /// Price overrides are used to update some or all prices in a plan for + /// the specific subscription being created. This is useful when a new customer + /// has negotiated a rate that is unique to the customer. + /// + /// To override prices, provide a list of objects with the key `price_overrides`. + /// The price object in the list of overrides is expected to contain the existing + /// price id, the `model_type` and configuration. (See the [Price resource](/product-catalog/price-configuration) + /// for the specification of different price model configurations.) The numerical + /// values can be updated, but the billable metric, cadence, type, and name of + /// a price can not be overridden. + /// + /// ### Maximums and Minimums Minimums and maximums, much like price overrides, + /// can be useful when a new customer has negotiated a new or different minimum + /// or maximum spend cap than the default for a given price. If one exists for + /// a price and null is provided for the minimum/maximum override on creation, + /// then there will be no minimum/maximum on the new subscription. If no value + /// is provided, then the default price maximum or minimum is used. + /// + /// To add a minimum for a specific price, add `minimum_amount` to the + /// specific price in the `price_overrides` object. + /// + /// To add a maximum for a specific price, add `maximum_amount` to the + /// specific price in the `price_overrides` object. + /// + /// ### Minimum override example + /// + /// Price minimum override example: + /// + /// ```json { ... "id": "price_id", "model_type": "unit", "unit_config": + /// { "unit_amount": "0.50" }, "minimum_amount": "100.00" ... } ``` + /// + /// Removing an existing minimum example ```json { ... "id": "price_id", + /// "model_type": "unit", "unit_config": { "unit_amount": "0.50" }, + /// "minimum_amount": null ... } ``` + /// + /// ### Discounts Discounts, like price overrides, can be useful when a + /// new customer has negotiated a new or different discount than the default for + /// a price. If a discount exists for a price and a null discount is provided + /// on creation, then there will be no discount on the new subscription. + /// + /// To add a discount for a specific price, add `discount` to the price + /// in the `price_overrides` object. Discount should be a dictionary of the format: + /// ```ts { "discount_type": "amount" | "percentage" | "usage", "amount_discount": + /// string, "percentage_discount": string, "usage_discount": string } ``` + /// where either `amount_discount`, `percentage_discount`, or `usage_discount` + /// is provided. + /// + /// Price discount example ```json { ... "id": "price_id", "model_type": + /// "unit", "unit_config": { "unit_amount": "0.50" }, "discount": {"discount_type": + /// "amount", "amount_discount": "175"}, } ``` + /// + /// Removing an existing discount example ```json { "customer_id": "customer_id", + /// "plan_id": "plan_id", "discount": null, "price_overrides": [ ... ] + /// ... } ``` + /// + /// ## Threshold Billing + /// + /// Orb supports invoicing for a subscription when a preconfigured usage + /// threshold is hit. To enable threshold billing, pass in an `invoicing_threshold`, + /// which is specified in the subscription's invoicing currency, when creating + /// a subscription. E.g. pass in `10.00` to issue an invoice when usage amounts + /// hit \$10.00 for a subscription that invoices in USD. + /// + /// ## Limits By default, Orb limits the number of subscriptions per customer + /// to 100. + /// + Task Create( + SubscriptionCreateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to update the `metadata`, `net terms`, `auto_collection`, + /// `invoicing_threshold`, and `default_invoice_memo` properties on a subscription. + /// + Task Update( + SubscriptionUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string subscriptionID, + SubscriptionUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a list of all subscriptions for an account as a [paginated](/api-reference/pagination) + /// list, ordered starting from the most recently created subscription. For a + /// full discussion of the subscription resource, see [Subscription](/core-concepts##subscription). + /// + /// Subscriptions can be filtered for a specific customer by using either + /// the customer_id or external_customer_id query parameters. To filter subscriptions + /// for multiple customers, use the customer_id[] or external_customer_id[] query parameters. + /// + Task List( + SubscriptionListParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to cancel an existing subscription. It returns + /// the serialized subscription object with an `end_date` parameter that signifies + /// when the subscription will transition to an ended state. + /// + /// The body parameter `cancel_option` determines the cancellation behavior. + /// Orb supports three cancellation options: - `end_of_subscription_term`: stops + /// the subscription from auto-renewing. Subscriptions that have been cancelled + /// with this option can still incur charges for the remainder of their term: + /// - Issuing this cancellation request for a monthly subscription will keep + /// the subscription active until the start of the subsequent month, and + /// potentially issue an invoice for any usage charges incurred in the intervening + /// period. - Issuing this cancellation request for a quarterly subscription + /// will keep the subscription active until the end of the quarter and + /// potentially issue an invoice for any usage charges incurred in the intervening + /// period. - Issuing this cancellation request for a yearly subscription + /// will keep the subscription active for the full year. For example, a + /// yearly subscription starting on 2021-11-01 and cancelled on 2021-12-08 will + /// remain active until 2022-11-01 and potentially issue charges in the + /// intervening months for any recurring monthly usage charges in its plan. + /// - **Note**: If a subscription's plan contains prices with difference cadences, + /// the end of term date will be determined by the largest cadence value. + /// For example, cancelling end of term for a subscription with a quarterly + /// fixed fee with a monthly usage fee will result in the subscription ending + /// at the end of the quarter. + /// + /// - `immediate`: ends the subscription immediately, setting the `end_date` + /// to the current time: - Subscriptions that have been cancelled with this + /// option will be invoiced immediately. This invoice will include any usage + /// fees incurred in the billing period up to the cancellation, along with any + /// prorated recurring fees for the billing period, if applicable. + /// - **Note**: If the subscription has a recurring fee that was paid in-advance, + /// the prorated amount for the remaining time period will be added to the + /// [customer's balance](list-balance-transactions) upon immediate cancellation. + /// However, if the customer is ineligible to use the customer balance, the subscription + /// cannot be cancelled immediately. + /// + /// - `requested_date`: ends the subscription on a specified date, which + /// requires a `cancellation_date` to be passed in. If no timezone is provided, + /// the customer's timezone is used. For example, a subscription starting on + /// January 1st with a monthly price can be set to be cancelled on the first + /// of any month after January 1st (e.g. March 1st, April 1st, May 1st). A + /// subscription with multiple prices with different cadences defines the "term" + /// to be the highest cadence of the prices. + /// + /// Upcoming subscriptions are only eligible for immediate cancellation, + /// which will set the `end_date` equal to the `start_date` upon cancellation. + /// + /// ## Backdated cancellations Orb allows you to cancel a subscription + /// in the past as long as there are no paid invoices between the `requested_date` + /// and the current time. If the cancellation is after the latest issued invoice, + /// Orb will generate a balance refund for the current period. If the cancellation + /// is before the most recently issued invoice, Orb will void the intervening + /// invoice and generate a new one based on the new dates for the subscription. + /// See the section on [cancellation behaviors](/product-catalog/creating-subscriptions#cancellation-behaviors). + /// + Task Cancel( + SubscriptionCancelParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Cancel( + string subscriptionID, + SubscriptionCancelParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a [Subscription](/core-concepts##subscription) + /// given an identifier. + /// + Task Fetch( + SubscriptionFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string subscriptionID, + SubscriptionFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a day-by-day snapshot of a subscription's + /// costs in Orb, calculated by applying pricing information to the underlying + /// usage (see the [subscription usage endpoint](fetch-subscription-usage) to + /// fetch usage per metric, in usage units rather than a currency). + /// + /// The semantics of this endpoint exactly mirror those of [fetching a customer's + /// costs](fetch-customer-costs). Use this endpoint to limit your analysis of + /// costs to a specific subscription for the customer (e.g. to de-aggregate costs + /// when a customer's subscription has started and stopped on the same day). + /// + Task FetchCosts( + SubscriptionFetchCostsParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task FetchCosts( + string subscriptionID, + SubscriptionFetchCostsParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a [paginated](/api-reference/pagination) list of all + /// plans associated with a subscription along with their start and end dates. + /// This list contains the subscription's initial plan along with past and future + /// plan changes. + /// + Task FetchSchedule( + SubscriptionFetchScheduleParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task FetchSchedule( + string subscriptionID, + SubscriptionFetchScheduleParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch a subscription's usage in Orb. Especially + /// when combined with optional query parameters, this endpoint is a powerful + /// way to build visualizations on top of Orb's event data and metrics. + /// + /// With no query parameters specified, this endpoint returns usage for + /// the subscription's _current billing period_ across each billable metric that + /// participates in the subscription. Usage quantities returned are the result + /// of evaluating the metric definition for the entirety of the customer's billing period. + /// + /// ### Default response shape Orb returns a `data` array with an object + /// corresponding to each billable metric. Nested within this object is a `usage` + /// array which has a `quantity` value and a corresponding `timeframe_start` + /// and `timeframe_end`. The `quantity` value represents the calculated usage + /// value for the billable metric over the specified timeframe (inclusive of + /// the `timeframe_start` timestamp and exclusive of the `timeframe_end` timestamp). + /// + /// Orb will include _every_ window in the response starting from the beginning + /// of the billing period, even when there were no events (and therefore no usage) + /// in the window. This increases the size of the response but prevents the caller + /// from filling in gaps and handling cumbersome time-based logic. + /// + /// The query parameters in this endpoint serve to override this behavior + /// and provide some key functionality, as listed below. Note that this functionality + /// can also be used _in conjunction_ with each other, e.g. to display grouped + /// usage on a custom timeframe. + /// + /// ## Custom timeframe In order to view usage for a custom timeframe rather + /// than the current billing period, specify a `timeframe_start` and `timeframe_end`. + /// This will calculate quantities for usage incurred between timeframe_start + /// (inclusive) and timeframe_end (exclusive), i.e. `[timeframe_start, timeframe_end)`. + /// + /// Note: - These timestamps must be specified in ISO 8601 format and UTC + /// timezone, e.g. `2022-02-01T05:00:00Z`. - Both parameters must be specified + /// if either is specified. + /// + /// ## Grouping by custom attributes In order to view a single metric grouped + /// by a specific _attribute_ that each event is tagged with (e.g. `cluster`), + /// you must additionally specify a `billable_metric_id` and a `group_by` key. + /// The `group_by` key denotes the event property on which to group. + /// + /// When returning grouped usage, only usage for `billable_metric_id` is + /// returned, and a separate object in the `data` array is returned for each + /// value of the `group_by` key present in your events. The `quantity` value + /// is the result of evaluating the billable metric for events filtered to a single + /// value of the `group_by` key. + /// + /// Orb expects that events that match the billable metric will contain + /// values in the `properties` dictionary that correspond to the `group_by` key + /// specified. By default, Orb will not return a `null` group (i.e. events that + /// match the metric but do not have the key set). Currently, it is only possible + /// to view usage grouped by a single attribute at a time. + /// + /// When viewing grouped usage, Orb uses pagination to limit the response + /// size to 1000 groups by default. If there are more groups for a given subscription, + /// pagination metadata in the response can be used to fetch all of the data. + /// + /// The following example shows usage for an "API Requests" billable metric + /// grouped by `region`. Note the extra `metric_group` dictionary in the response, + /// which provides metadata about the group: + /// + /// ```json { "data": [ { "usage": [ + /// { "quantity": 0.19291, "timeframe_start": + /// "2021-10-01T07:00:00Z", "timeframe_end": "2021-10-02T07:00:00Z", + /// }, ... ], "metric_group": + /// { "property_key": "region", "property_value": + /// "asia/pacific" }, "billable_metric": { + /// "id": "Fe9pbpMk86xpwdGB", "name": "API Requests" + /// }, "view_mode": "periodic" }, ... + /// ] } ``` + /// + /// ## Windowed usage The `granularity` parameter can be used to _window_ + /// the usage `quantity` value into periods. When not specified, usage is returned + /// for the entirety of the time range. + /// + /// When `granularity = day` is specified with a timeframe longer than a + /// day, Orb will return a `quantity` value for each full day between `timeframe_start` + /// and `timeframe_end`. Note that the days are demarcated by the _customer's + /// local midnight_. + /// + /// For example, with `timeframe_start = 2022-02-01T05:00:00Z`, `timeframe_end + /// = 2022-02-04T01:00:00Z` and `granularity=day`, the following windows will + /// be returned for a customer in the `America/Los_Angeles` timezone since local + /// midnight is `08:00` UTC: - `[2022-02-01T05:00:00Z, 2022-02-01T08:00:00Z)` + /// - `[2022-02-01T08:00:00, 2022-02-02T08:00:00Z)` - `[2022-02-02T08:00:00, + /// 2022-02-03T08:00:00Z)` - `[2022-02-03T08:00:00, 2022-02-04T01:00:00Z)` + /// + /// ```json { "data": [ { "billable_metric": { + /// "id": "Q8w89wjTtBdejXKsm", "name": "API Requests" + /// }, "usage": [ { + /// "quantity": 0, "timeframe_end": "2022-02-01T08:00:00+00:00", + /// "timeframe_start": "2022-02-01T05:00:00+00:00" + /// }, { + /// + /// "quantity": 0, "timeframe_end": + /// "2022-02-02T08:00:00+00:00", "timeframe_start": "2022-02-01T08:00:00+00:00" + /// }, { "quantity": 0, + /// "timeframe_end": "2022-02-03T08:00:00+00:00", + /// "timeframe_start": "2022-02-02T08:00:00+00:00" + /// }, { "quantity": 0, + /// "timeframe_end": "2022-02-04T01:00:00+00:00", "timeframe_start": + /// "2022-02-03T08:00:00+00:00" } ], + /// "view_mode": "periodic" }, ... ] } ``` + /// + /// ## Decomposable vs. non-decomposable metrics Billable metrics fall + /// into one of two categories: decomposable and non-decomposable. A decomposable + /// billable metric, such as a sum or a count, can be displayed and aggregated + /// across arbitrary timescales. On the other hand, a non-decomposable metric + /// is not meaningful when only a slice of the billing window is considered. + /// + /// As an example, if we have a billable metric that's defined to count + /// unique users, displaying a graph of unique users for each day is not representative + /// of the billable metric value over the month (days could have an overlapping + /// set of 'unique' users). Instead, what's useful for any given day is the number + /// of unique users in the billing period so far, which are the _cumulative_ unique users. + /// + /// Accordingly, this endpoint returns treats these two types of metrics + /// differently when `group_by` is specified: - Decomposable metrics can be grouped + /// by any event property. - Non-decomposable metrics can only be grouped by the + /// corresponding price's invoice grouping key. If no invoice grouping key is + /// present, the metric does not support `group_by`. + /// + /// ## Matrix prices When a billable metric is attached to a price that + /// uses matrix pricing, it's important to view usage grouped by those matrix + /// dimensions. In this case, use the query parameters `first_dimension_key`, + /// `first_dimension_value` and `second_dimension_key`, `second_dimension_value` + /// while filtering to a specific `billable_metric_id`. + /// + /// For example, if your compute metric has a separate unit price (i.e. + /// a matrix pricing model) per `region` and `provider`, your request might provide + /// the following parameters: + /// + /// - `first_dimension_key`: `region` - `first_dimension_value`: `us-east-1` + /// - `second_dimension_key`: `provider` - `second_dimension_value`: `aws` + /// + Task FetchUsage( + SubscriptionFetchUsageParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task FetchUsage( + string subscriptionID, + SubscriptionFetchUsageParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to add and edit subscription [price intervals](/api-reference/price-interval/add-or-edit-price-intervals). + /// By making modifications to a subscription’s price intervals, you can [flexibly + /// and atomically control the billing behavior of a subscription](/product-catalog/modifying-subscriptions). + /// + /// ## Adding price intervals + /// + /// Prices can be added as price intervals to a subscription by specifying + /// them in the `add` array. A `price_id` or `external_price_id` from an add-on + /// price or previously removed plan price can be specified to reuse an existing + /// price definition (however, please note that prices from other plans cannot + /// be added to the subscription). Additionally, a new price can be specified + /// using the `price` field — this price will be created automatically. + /// + /// A `start_date` must be specified for the price interval. This is the + /// date when the price will start billing on the subscription, so this will notably + /// result in an immediate charge at this time for any billed in advance fixed + /// fees. The `end_date` will default to null, resulting in a price interval + /// that will bill on a continually recurring basis. Both of these dates can be + /// set in the past or the future and Orb will generate or modify invoices to + /// ensure the subscription’s invoicing behavior is correct. + /// + /// Additionally, a discount, minimum, or maximum can be specified on the + /// price interval. This will only apply to this price interval, not any other + /// price intervals on the subscription. + /// + /// ## Adjustment intervals + /// + /// An adjustment interval represents the time period that a particular + /// adjustment (a discount, minimum, or maximum) applies to the prices on a subscription. + /// Adjustment intervals can be added to a subscription by specifying them in + /// the `add_adjustments` array, or modified via the `edit_adjustments` array. + /// When creating an adjustment interval, you'll need to provide the definition + /// of the new adjustment (the type of adjustment, and which prices it applies + /// to), as well as the start and end dates for the adjustment interval. The + /// start and end dates of an existing adjustment interval can be edited via the + /// `edit_adjustments` field (just like price intervals). (To "change" the amount + /// of a discount, minimum, or maximum, then, you'll need to end the existing + /// interval, and create a new adjustment interval with the new amount and a + /// start date that matches the end date of the previous interval.) + /// + /// ## Editing price intervals + /// + /// Price intervals can be adjusted by specifying edits to make in the + /// `edit` array. A `price_interval_id` to edit must be specified — this can + /// be retrieved from the `price_intervals` field on the subscription. + /// + /// A new `start_date` or `end_date` can be specified to change the range + /// of the price interval, which will modify past or future invoices to ensure + /// correctness. If either of these dates are unspecified, they will default + /// to the existing date on the price interval. To remove a price interval entirely + /// from a subscription, set the `end_date` to be equivalent to the `start_date`. + /// + /// ## Fixed fee quantity transitions The fixed fee quantity transitions + /// for a fixed fee price interval can also be specified when adding or editing + /// by passing an array for `fixed_fee_quantity_transitions`. A fixed fee quantity + /// transition must have a `quantity` and an `effective_date`, which is the date + /// after which the new quantity will be used for billing. If a fixed fee quantity + /// transition is scheduled at a billing period boundary, the full quantity will + /// be billed on an invoice with the other prices on the subscription. If the + /// fixed fee quantity transition is scheduled mid-billing period, the difference + /// between the existing quantity and quantity specified in the transition will + /// be prorated for the rest of the billing period and billed immediately, which + /// will generate a new invoice. + /// + /// Notably, the list of fixed fee quantity transitions passed will overwrite + /// the existing fixed fee quantity transitions on the price interval, so the + /// entire list of transitions must be specified to add additional transitions. + /// The existing list of transitions can be retrieved using the `fixed_fee_quantity_transitions` + /// property on a subscription’s serialized price intervals. + /// + Task PriceIntervals( + SubscriptionPriceIntervalsParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task PriceIntervals( + string subscriptionID, + SubscriptionPriceIntervalsParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// Redeem a coupon effective at a given time. + /// + Task RedeemCoupon( + SubscriptionRedeemCouponParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task RedeemCoupon( + string subscriptionID, + SubscriptionRedeemCouponParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to change an existing subscription's plan. It returns + /// the serialized updated subscription object. + /// + /// The body parameter `change_option` determines when the plan change occurs. + /// Orb supports three options: - `end_of_subscription_term`: changes the plan + /// at the end of the existing plan's term. - Issuing this plan change request + /// for a monthly subscription will keep the existing plan active until the start + /// of the subsequent month. Issuing this plan change request for a yearly + /// subscription will keep the existing plan active for the full year. Charges + /// incurred in the remaining period will be invoiced as normal. - Example: + /// The plan is billed monthly on the 1st of the month, the request is made on + /// January 15th, so the plan will be changed on February 1st, and invoice + /// will be issued on February 1st for the last month of the original plan. - + /// `immediate`: changes the plan immediately. - Subscriptions that have their + /// plan changed with this option will move to the new plan immediately, and be + /// invoiced immediately. - This invoice will include any usage fees + /// incurred in the billing period up to the change, along with any prorated + /// recurring fees for the billing period, if applicable. - Example: + /// The plan is billed monthly on the 1st of the month, the request is made on + /// January 15th, so the plan will be changed on January 15th, and an invoice + /// will be issued for the partial month, from January 1 to January 15, on the + /// original plan. - `requested_date`: changes the plan on the requested + /// date (`change_date`). - If no timezone is provided, the customer's timezone + /// is used. The `change_date` body parameter is required if this option + /// is chosen. - Example: The plan is billed monthly on the 1st of the + /// month, the request is made on January 15th, with a requested `change_date` + /// of February 15th, so the plan will be changed on February 15th, and invoices + /// will be issued on February 1st and February 15th. + /// + /// Note that one of `plan_id` or `external_plan_id` is required in the + /// request body for this operation. + /// + /// ## Customize your customer's subscriptions + /// + /// Prices and adjustments in a plan can be added, removed, or replaced + /// on the subscription when you schedule the plan change. This is useful when + /// a customer has prices that differ from the default prices for a specific plan. + /// + /// This feature is only available for accounts that have migrated + /// to Subscription Overrides Version 2. You can find your Subscription Overrides + /// Version at the bottom of your [Plans page](https://app.withorb.com/plans) + /// + /// ### Adding Prices + /// + /// To add prices, provide a list of objects with the key `add_prices`. + /// An object in the list must specify an existing add-on price with a `price_id` + /// or `external_price_id` field, or create a new add-on price by including an + /// object with the key `price`, identical to what would be used in the request + /// body for the [create price endpoint](/api-reference/price/create-price). + /// See the [Price resource](/product-catalog/price-configuration) for the specification + /// of different price model configurations possible in this object. + /// + /// If the plan has phases, each object in the list must include a number + /// with `plan_phase_order` key to indicate which phase the price should be added to. + /// + /// An object in the list can specify an optional `start_date` and optional + /// `end_date`. If `start_date` is unspecified, the start of the phase / plan + /// change time will be used. If `end_date` is unspecified, it will finish at + /// the end of the phase / have no end time. + /// + /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, + /// or `discounts`. This will create adjustments which apply only to this price. + /// + /// Additionally, an object in the list can specify an optional `reference_id`. + /// This ID can be used to reference this price when [adding an adjustment](#adding-adjustments) + /// in the same API call. However the ID is _transient_ and cannot be used to + /// refer to the price in future API calls. + /// + /// ### Removing Prices + /// + /// To remove prices, provide a list of objects with the key `remove_prices`. + /// An object in the list must specify a plan price with either a `price_id` + /// or `external_price_id` field. + /// + /// ### Replacing Prices + /// + /// To replace prices, provide a list of objects with the key `replace_prices`. + /// An object in the list must specify a plan price to replace with the `replaces_price_id` + /// key, and it must specify a price to replace it with by either referencing + /// an existing add-on price with a `price_id` or `external_price_id` field, or + /// by creating a new add-on price by including an object with the key `price`, + /// identical to what would be used in the request body for the [create price + /// endpoint](/api-reference/price/create-price). See the [Price resource](/product-catalog/price-configuration) + /// for the specification of different price model configurations possible in + /// this object. + /// + /// For fixed fees, an object in the list can supply a `fixed_price_quantity` + /// instead of a `price`, `price_id`, or `external_price_id` field. This will + /// update only the quantity for the price, similar to the [Update price quantity](/api-reference/subscription/update-price-quantity) endpoint. + /// + /// The replacement price will have the same phase, if applicable, and the + /// same start and end dates as the price it replaces. + /// + /// An object in the list can specify an optional `minimum_amount`, `maximum_amount`, + /// or `discounts`. This will create adjustments which apply only to this price. + /// + /// Additionally, an object in the list can specify an optional `reference_id`. + /// This ID can be used to reference the replacement price when [adding an adjustment](#adding-adjustments) + /// in the same API call. However the ID is _transient_ and cannot be used to + /// refer to the price in future API calls. + /// + /// ### Adding adjustments + /// + /// To add adjustments, provide a list of objects with the key `add_adjustments`. + /// An object in the list must include an object with the key `adjustment`, identical + /// to the adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). + /// + /// If the plan has phases, each object in the list must include a number + /// with `plan_phase_order` key to indicate which phase the adjustment should + /// be added to. + /// + /// An object in the list can specify an optional `start_date` and optional + /// `end_date`. If `start_date` is unspecified, the start of the phase / plan + /// change time will be used. If `end_date` is unspecified, it will finish at + /// the end of the phase / have no end time. + /// + /// ### Removing adjustments + /// + /// To remove adjustments, provide a list of objects with the key `remove_adjustments`. + /// An object in the list must include a key, `adjustment_id`, with the ID of + /// the adjustment to be removed. + /// + /// ### Replacing adjustments + /// + /// To replace adjustments, provide a list of objects with the key `replace_adjustments`. + /// An object in the list must specify a plan adjustment to replace with the + /// `replaces_adjustment_id` key, and it must specify an adjustment to replace + /// it with by including an object with the key `adjustment`, identical to the + /// adjustment object in the [add/edit price intervals endpoint](/api-reference/price-interval/add-or-edit-price-intervals). + /// + /// The replacement adjustment will have the same phase, if applicable, + /// and the same start and end dates as the adjustment it replaces. + /// + /// ## Price overrides (DEPRECATED) + /// + /// Price overrides are being phased out in favor adding/removing/replacing + /// prices. (See [Customize your customer's subscriptions](/api-reference/subscription/schedule-plan-change)) + /// + /// Price overrides are used to update some or all prices in a plan for + /// the specific subscription being created. This is useful when a new customer + /// has negotiated a rate that is unique to the customer. + /// + /// To override prices, provide a list of objects with the key `price_overrides`. + /// The price object in the list of overrides is expected to contain the existing + /// price id, the `model_type` and configuration. (See the [Price resource](/product-catalog/price-configuration) + /// for the specification of different price model configurations.) The numerical + /// values can be updated, but the billable metric, cadence, type, and name of + /// a price can not be overridden. + /// + /// ### Maximums, and minimums Price overrides are used to update some or + /// all prices in the target plan. Minimums and maximums, much like price overrides, + /// can be useful when a new customer has negotiated a new or different minimum + /// or maximum spend cap than the default for the plan. The request format for + /// maximums and minimums is the same as those in [subscription creation](create-subscription). + /// + /// ## Scheduling multiple plan changes When scheduling multiple plan changes + /// with the same date, the latest plan change on that day takes effect. + /// + /// ## Prorations for in-advance fees By default, Orb calculates the prorated + /// difference in any fixed fees when making a plan change, adjusting the customer + /// balance as needed. For details on this behavior, see [Modifying subscriptions](/product-catalog/modifying-subscriptions#prorations-for-in-advance-fees). + /// + Task SchedulePlanChange( + SubscriptionSchedulePlanChangeParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task SchedulePlanChange( + string subscriptionID, + SubscriptionSchedulePlanChangeParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// Manually trigger a phase, effective the given date (or the current time, + /// if not specified). + /// + Task TriggerPhase( + SubscriptionTriggerPhaseParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task TriggerPhase( + string subscriptionID, + SubscriptionTriggerPhaseParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to unschedule any pending cancellations for a subscription. + /// + /// To be eligible, the subscription must currently be active and have a + /// future cancellation. This operation will turn on auto-renew, ensuring that + /// the subscription does not end at the currently scheduled cancellation time. + /// + Task UnscheduleCancellation( + SubscriptionUnscheduleCancellationParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task UnscheduleCancellation( + string subscriptionID, + SubscriptionUnscheduleCancellationParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to clear scheduled updates to the quantity for a + /// fixed fee. + /// + /// If there are no updates scheduled, a request validation error will be + /// returned with a 400 status code. + /// + Task UnscheduleFixedFeeQuantityUpdates( + SubscriptionUnscheduleFixedFeeQuantityUpdatesParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task UnscheduleFixedFeeQuantityUpdates( + string subscriptionID, + SubscriptionUnscheduleFixedFeeQuantityUpdatesParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to unschedule any pending plan changes on an existing + /// subscription. When called, all upcoming plan changes will be unscheduled. + /// + Task UnschedulePendingPlanChanges( + SubscriptionUnschedulePendingPlanChangesParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task UnschedulePendingPlanChanges( + string subscriptionID, + SubscriptionUnschedulePendingPlanChangesParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint can be used to update the quantity for a fixed fee. + /// + /// To be eligible, the subscription must currently be active and the price + /// specified must be a fixed fee (not usage-based). This operation will immediately + /// update the quantity for the fee, or if a `effective_date` is passed in, will + /// update the quantity on the requested date at midnight in the customer's timezone. + /// + /// In order to change the fixed fee quantity as of the next draft invoice + /// for this subscription, pass `change_option=upcoming_invoice` without an `effective_date` specified. + /// + /// If the fee is an in-advance fixed fee, it will also issue an immediate + /// invoice for the difference for the remainder of the billing period. + /// + Task UpdateFixedFeeQuantity( + SubscriptionUpdateFixedFeeQuantityParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task UpdateFixedFeeQuantity( + string subscriptionID, + SubscriptionUpdateFixedFeeQuantityParams parameters, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to update the trial end date for a subscription. The + /// new trial end date must be within the time range of the current plan (i.e. + /// the new trial end date must be on or after the subscription's start date on + /// the current plan, and on or before the subscription end date). + /// + /// In order to retroactively remove a trial completely, the end date can + /// be set to the transition date of the subscription to this plan (or, if this + /// is the first plan for this subscription, the subscription's start date). + /// In order to end a trial immediately, the keyword `immediate` can be provided + /// as the trial end date. + /// + /// By default, Orb will shift only the trial end date (and price intervals + /// that start or end on the previous trial end date), and leave all other future + /// price intervals untouched. If the `shift` parameter is set to `true`, Orb + /// will shift all subsequent price and adjustment intervals by the same amount + /// as the trial end date shift (so, e.g., if a plan change is scheduled or an + /// add-on price was added, that change will be pushed back by the same amount + /// of time the trial is extended). + /// + Task UpdateTrial( + SubscriptionUpdateTrialParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task UpdateTrial( + string subscriptionID, + SubscriptionUpdateTrialParams parameters, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/ITopLevelService.cs b/src/Orb/Services/ITopLevelService.cs new file mode 100644 index 00000000..a2445959 --- /dev/null +++ b/src/Orb/Services/ITopLevelService.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.TopLevel; + +namespace Orb.Services; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface ITopLevelService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + ITopLevelService WithOptions(Func modifier); + + /// + /// This endpoint allows you to test your connection to the Orb API and check + /// the validity of your API key, passed in the Authorization header. This is + /// particularly useful for checking that your environment is set up properly, + /// and is a great choice for connectors and integrations. + /// + /// This API does not have any side-effects or return any Orb resources. + /// + Task Ping( + TopLevelPingParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/InvoiceLineItemService.cs b/src/Orb/Services/InvoiceLineItemService.cs new file mode 100644 index 00000000..e7c6ea52 --- /dev/null +++ b/src/Orb/Services/InvoiceLineItemService.cs @@ -0,0 +1,49 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.InvoiceLineItems; + +namespace Orb.Services; + +/// +public sealed class InvoiceLineItemService : IInvoiceLineItemService +{ + /// + public IInvoiceLineItemService WithOptions(Func modifier) + { + return new InvoiceLineItemService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public InvoiceLineItemService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + InvoiceLineItemCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoiceLineItem = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoiceLineItem.Validate(); + } + return invoiceLineItem; + } +} diff --git a/src/Orb/Services/InvoiceService.cs b/src/Orb/Services/InvoiceService.cs new file mode 100644 index 00000000..ad46ceeb --- /dev/null +++ b/src/Orb/Services/InvoiceService.cs @@ -0,0 +1,331 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Invoices; + +namespace Orb.Services; + +/// +public sealed class InvoiceService : IInvoiceService +{ + /// + public IInvoiceService WithOptions(Func modifier) + { + return new InvoiceService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public InvoiceService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + InvoiceCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task Update( + InvoiceUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.InvoiceID == null) + { + throw new OrbInvalidDataException("'parameters.InvoiceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task Update( + string invoiceID, + InvoiceUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update(parameters with { InvoiceID = invoiceID }, cancellationToken); + } + + /// + public async Task List( + InvoiceListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new InvoiceListPage(this, parameters, page); + } + + /// + public async Task Fetch( + InvoiceFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.InvoiceID == null) + { + throw new OrbInvalidDataException("'parameters.InvoiceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task Fetch( + string invoiceID, + InvoiceFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { InvoiceID = invoiceID }, cancellationToken); + } + + /// + public async Task FetchUpcoming( + InvoiceFetchUpcomingParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Issue( + InvoiceIssueParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.InvoiceID == null) + { + throw new OrbInvalidDataException("'parameters.InvoiceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task Issue( + string invoiceID, + InvoiceIssueParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Issue(parameters with { InvoiceID = invoiceID }, cancellationToken); + } + + /// + public async Task MarkPaid( + InvoiceMarkPaidParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.InvoiceID == null) + { + throw new OrbInvalidDataException("'parameters.InvoiceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task MarkPaid( + string invoiceID, + InvoiceMarkPaidParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.MarkPaid(parameters with { InvoiceID = invoiceID }, cancellationToken); + } + + /// + public async Task Pay( + InvoicePayParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.InvoiceID == null) + { + throw new OrbInvalidDataException("'parameters.InvoiceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task Pay( + string invoiceID, + InvoicePayParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Pay(parameters with { InvoiceID = invoiceID }, cancellationToken); + } + + /// + public async Task Void( + InvoiceVoidParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.InvoiceID == null) + { + throw new OrbInvalidDataException("'parameters.InvoiceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var invoice = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + invoice.Validate(); + } + return invoice; + } + + /// + public async Task Void( + string invoiceID, + InvoiceVoidParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Void(parameters with { InvoiceID = invoiceID }, cancellationToken); + } +} diff --git a/src/Orb/Services/ItemService.cs b/src/Orb/Services/ItemService.cs new file mode 100644 index 00000000..9e96aae2 --- /dev/null +++ b/src/Orb/Services/ItemService.cs @@ -0,0 +1,191 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Items; + +namespace Orb.Services; + +/// +public sealed class ItemService : IItemService +{ + /// + public IItemService WithOptions(Func modifier) + { + return new ItemService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public ItemService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + ItemCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var item = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + item.Validate(); + } + return item; + } + + /// + public async Task Update( + ItemUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ItemID == null) + { + throw new OrbInvalidDataException("'parameters.ItemID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var item = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + item.Validate(); + } + return item; + } + + /// + public async Task Update( + string itemID, + ItemUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update(parameters with { ItemID = itemID }, cancellationToken); + } + + /// + public async Task List( + ItemListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new ItemListPage(this, parameters, page); + } + + /// + public async Task Archive( + ItemArchiveParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ItemID == null) + { + throw new OrbInvalidDataException("'parameters.ItemID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var item = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + item.Validate(); + } + return item; + } + + /// + public async Task Archive( + string itemID, + ItemArchiveParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Archive(parameters with { ItemID = itemID }, cancellationToken); + } + + /// + public async Task Fetch( + ItemFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ItemID == null) + { + throw new OrbInvalidDataException("'parameters.ItemID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var item = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + item.Validate(); + } + return item; + } + + /// + public async Task Fetch( + string itemID, + ItemFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { ItemID = itemID }, cancellationToken); + } +} diff --git a/src/Orb/Services/MetricService.cs b/src/Orb/Services/MetricService.cs new file mode 100644 index 00000000..a8b826b1 --- /dev/null +++ b/src/Orb/Services/MetricService.cs @@ -0,0 +1,158 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Metrics; + +namespace Orb.Services; + +/// +public sealed class MetricService : IMetricService +{ + /// + public IMetricService WithOptions(Func modifier) + { + return new MetricService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public MetricService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + MetricCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var billableMetric = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + billableMetric.Validate(); + } + return billableMetric; + } + + /// + public async Task Update( + MetricUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.MetricID == null) + { + throw new OrbInvalidDataException("'parameters.MetricID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var billableMetric = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + billableMetric.Validate(); + } + return billableMetric; + } + + /// + public async Task Update( + string metricID, + MetricUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update(parameters with { MetricID = metricID }, cancellationToken); + } + + /// + public async Task List( + MetricListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new MetricListPage(this, parameters, page); + } + + /// + public async Task Fetch( + MetricFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.MetricID == null) + { + throw new OrbInvalidDataException("'parameters.MetricID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var billableMetric = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + billableMetric.Validate(); + } + return billableMetric; + } + + /// + public async Task Fetch( + string metricID, + MetricFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { MetricID = metricID }, cancellationToken); + } +} diff --git a/src/Orb/Services/PlanService.cs b/src/Orb/Services/PlanService.cs new file mode 100644 index 00000000..7ac12152 --- /dev/null +++ b/src/Orb/Services/PlanService.cs @@ -0,0 +1,160 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Plans; +using Orb.Services.Plans; + +namespace Orb.Services; + +/// +public sealed class PlanService : IPlanService +{ + /// + public IPlanService WithOptions(Func modifier) + { + return new PlanService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public PlanService(IOrbClient client) + { + _client = client; + _externalPlanID = new(() => new ExternalPlanIDService(client)); + } + + readonly Lazy _externalPlanID; + public IExternalPlanIDService ExternalPlanID + { + get { return _externalPlanID.Value; } + } + + /// + public async Task Create( + PlanCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task Update( + PlanUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PlanID == null) + { + throw new OrbInvalidDataException("'parameters.PlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task Update( + string planID, + PlanUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update(parameters with { PlanID = planID }, cancellationToken); + } + + /// + public async Task List( + PlanListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new PlanListPage(this, parameters, page); + } + + /// + public async Task Fetch( + PlanFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PlanID == null) + { + throw new OrbInvalidDataException("'parameters.PlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task Fetch( + string planID, + PlanFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { PlanID = planID }, cancellationToken); + } +} diff --git a/src/Orb/Services/Plans/ExternalPlanIDService.cs b/src/Orb/Services/Plans/ExternalPlanIDService.cs new file mode 100644 index 00000000..90e32c39 --- /dev/null +++ b/src/Orb/Services/Plans/ExternalPlanIDService.cs @@ -0,0 +1,117 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Plans; +using Orb.Models.Plans.ExternalPlanID; + +namespace Orb.Services.Plans; + +/// +public sealed class ExternalPlanIDService : IExternalPlanIDService +{ + /// + public IExternalPlanIDService WithOptions(Func modifier) + { + return new ExternalPlanIDService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public ExternalPlanIDService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Update( + ExternalPlanIDUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.OtherExternalPlanID == null) + { + throw new OrbInvalidDataException("'parameters.OtherExternalPlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task Update( + string otherExternalPlanID, + ExternalPlanIDUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update( + parameters with + { + OtherExternalPlanID = otherExternalPlanID, + }, + cancellationToken + ); + } + + /// + public async Task Fetch( + ExternalPlanIDFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalPlanID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalPlanID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var plan = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + plan.Validate(); + } + return plan; + } + + /// + public async Task Fetch( + string externalPlanID, + ExternalPlanIDFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch( + parameters with + { + ExternalPlanID = externalPlanID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Plans/IExternalPlanIDService.cs b/src/Orb/Services/Plans/IExternalPlanIDService.cs new file mode 100644 index 00000000..fa0e3f4d --- /dev/null +++ b/src/Orb/Services/Plans/IExternalPlanIDService.cs @@ -0,0 +1,69 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.Plans; +using Orb.Models.Plans.ExternalPlanID; + +namespace Orb.Services.Plans; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IExternalPlanIDService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IExternalPlanIDService WithOptions(Func modifier); + + /// + /// This endpoint can be used to update the `external_plan_id`, and `metadata` + /// of an existing plan. + /// + /// Other fields on a plan are currently immutable. + /// + Task Update( + ExternalPlanIDUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string otherExternalPlanID, + ExternalPlanIDUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint is used to fetch [plan](/core-concepts##plan-and-price) details + /// given an external_plan_id identifier. It returns information about the prices + /// included in the plan and their configuration, as well as the product that + /// the plan is attached to. + /// + /// If multiple plans are found to contain the specified external_plan_id, + /// the active plans will take priority over archived ones, and among those, + /// the endpoint will return the most recently created plan. + /// + /// ## Serialized prices Orb supports a few different pricing models out + /// of the box. Each of these models is serialized differently in a given [Price](/core-concepts#plan-and-price) + /// object. The `model_type` field determines the key for the configuration object + /// that is present. A detailed explanation of price types can be found in the + /// [Price schema](/core-concepts#plan-and-price). " + /// + Task Fetch( + ExternalPlanIDFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string externalPlanID, + ExternalPlanIDFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/PriceService.cs b/src/Orb/Services/PriceService.cs new file mode 100644 index 00000000..cadd0cc2 --- /dev/null +++ b/src/Orb/Services/PriceService.cs @@ -0,0 +1,254 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.Prices; +using Orb.Services.Prices; +using Models = Orb.Models; + +namespace Orb.Services; + +/// +public sealed class PriceService : IPriceService +{ + /// + public IPriceService WithOptions(Func modifier) + { + return new PriceService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public PriceService(IOrbClient client) + { + _client = client; + _externalPriceID = new(() => new ExternalPriceIDService(client)); + } + + readonly Lazy _externalPriceID; + public IExternalPriceIDService ExternalPriceID + { + get { return _externalPriceID.Value; } + } + + /// + public async Task Create( + PriceCreateParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var price = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + price.Validate(); + } + return price; + } + + /// + public async Task Update( + PriceUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PriceID == null) + { + throw new OrbInvalidDataException("'parameters.PriceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var price = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + price.Validate(); + } + return price; + } + + /// + public async Task Update( + string priceID, + PriceUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update(parameters with { PriceID = priceID }, cancellationToken); + } + + /// + public async Task List( + PriceListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new PriceListPage(this, parameters, page); + } + + /// + public async Task Evaluate( + PriceEvaluateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PriceID == null) + { + throw new OrbInvalidDataException("'parameters.PriceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Evaluate( + string priceID, + PriceEvaluateParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.Evaluate(parameters with { PriceID = priceID }, cancellationToken); + } + + /// + public async Task EvaluateMultiple( + PriceEvaluateMultipleParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task EvaluatePreviewEvents( + PriceEvaluatePreviewEventsParams parameters, + CancellationToken cancellationToken = default + ) + { + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Fetch( + PriceFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.PriceID == null) + { + throw new OrbInvalidDataException("'parameters.PriceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var price = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + price.Validate(); + } + return price; + } + + /// + public async Task Fetch( + string priceID, + PriceFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch(parameters with { PriceID = priceID }, cancellationToken); + } +} diff --git a/src/Orb/Services/Prices/ExternalPriceIDService.cs b/src/Orb/Services/Prices/ExternalPriceIDService.cs new file mode 100644 index 00000000..f232b7f5 --- /dev/null +++ b/src/Orb/Services/Prices/ExternalPriceIDService.cs @@ -0,0 +1,117 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models; +using Orb.Models.Prices.ExternalPriceID; + +namespace Orb.Services.Prices; + +/// +public sealed class ExternalPriceIDService : IExternalPriceIDService +{ + /// + public IExternalPriceIDService WithOptions(Func modifier) + { + return new ExternalPriceIDService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public ExternalPriceIDService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Update( + ExternalPriceIDUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalPriceID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalPriceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var price = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + price.Validate(); + } + return price; + } + + /// + public async Task Update( + string externalPriceID, + ExternalPriceIDUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update( + parameters with + { + ExternalPriceID = externalPriceID, + }, + cancellationToken + ); + } + + /// + public async Task Fetch( + ExternalPriceIDFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.ExternalPriceID == null) + { + throw new OrbInvalidDataException("'parameters.ExternalPriceID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var price = await response.Deserialize(cancellationToken).ConfigureAwait(false); + if (this._client.ResponseValidation) + { + price.Validate(); + } + return price; + } + + /// + public async Task Fetch( + string externalPriceID, + ExternalPriceIDFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch( + parameters with + { + ExternalPriceID = externalPriceID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/Prices/IExternalPriceIDService.cs b/src/Orb/Services/Prices/IExternalPriceIDService.cs new file mode 100644 index 00000000..8920e484 --- /dev/null +++ b/src/Orb/Services/Prices/IExternalPriceIDService.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models; +using Orb.Models.Prices.ExternalPriceID; + +namespace Orb.Services.Prices; + +/// +/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking +/// changes in non-major versions. We may add new methods in the future that cause +/// existing derived classes to break. +/// +public interface IExternalPriceIDService +{ + /// + /// Returns a view of this service with the given option modifications applied. + /// + /// The original service is not modified. + /// + IExternalPriceIDService WithOptions(Func modifier); + + /// + /// This endpoint allows you to update the `metadata` property on a price. If + /// you pass null for the metadata value, it will clear any existing metadata + /// for that price. + /// + Task Update( + ExternalPriceIDUpdateParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Update( + string externalPriceID, + ExternalPriceIDUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ); + + /// + /// This endpoint returns a price given an external price id. See the [price creation + /// API](/api-reference/price/create-price) for more information about external + /// price aliases. + /// + Task Fetch( + ExternalPriceIDFetchParams parameters, + CancellationToken cancellationToken = default + ); + + /// + Task Fetch( + string externalPriceID, + ExternalPriceIDFetchParams? parameters = null, + CancellationToken cancellationToken = default + ); +} diff --git a/src/Orb/Services/SubscriptionChangeService.cs b/src/Orb/Services/SubscriptionChangeService.cs new file mode 100644 index 00000000..fc69f1f6 --- /dev/null +++ b/src/Orb/Services/SubscriptionChangeService.cs @@ -0,0 +1,167 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.SubscriptionChanges; + +namespace Orb.Services; + +/// +public sealed class SubscriptionChangeService : ISubscriptionChangeService +{ + /// + public ISubscriptionChangeService WithOptions(Func modifier) + { + return new SubscriptionChangeService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public SubscriptionChangeService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Retrieve( + SubscriptionChangeRetrieveParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionChangeID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionChangeID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var subscriptionChange = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + subscriptionChange.Validate(); + } + return subscriptionChange; + } + + /// + public async Task Retrieve( + string subscriptionChangeID, + SubscriptionChangeRetrieveParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Retrieve( + parameters with + { + SubscriptionChangeID = subscriptionChangeID, + }, + cancellationToken + ); + } + + /// + public async Task Apply( + SubscriptionChangeApplyParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionChangeID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionChangeID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Apply( + string subscriptionChangeID, + SubscriptionChangeApplyParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Apply( + parameters with + { + SubscriptionChangeID = subscriptionChangeID, + }, + cancellationToken + ); + } + + /// + public async Task Cancel( + SubscriptionChangeCancelParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionChangeID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionChangeID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task Cancel( + string subscriptionChangeID, + SubscriptionChangeCancelParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Cancel( + parameters with + { + SubscriptionChangeID = subscriptionChangeID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/SubscriptionService.cs b/src/Orb/Services/SubscriptionService.cs new file mode 100644 index 00000000..ec18056b --- /dev/null +++ b/src/Orb/Services/SubscriptionService.cs @@ -0,0 +1,772 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Exceptions; +using Orb.Models.SubscriptionChanges; +using Orb.Models.Subscriptions; + +namespace Orb.Services; + +/// +public sealed class SubscriptionService : ISubscriptionService +{ + /// + public ISubscriptionService WithOptions(Func modifier) + { + return new SubscriptionService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public SubscriptionService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Create( + SubscriptionCreateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task Update( + SubscriptionUpdateParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Put, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var subscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + subscription.Validate(); + } + return subscription; + } + + /// + public async Task Update( + string subscriptionID, + SubscriptionUpdateParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Update( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task List( + SubscriptionListParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new SubscriptionListPage(this, parameters, page); + } + + /// + public async Task Cancel( + SubscriptionCancelParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task Cancel( + string subscriptionID, + SubscriptionCancelParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.Cancel( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task Fetch( + SubscriptionFetchParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var subscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + subscription.Validate(); + } + return subscription; + } + + /// + public async Task Fetch( + string subscriptionID, + SubscriptionFetchParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.Fetch( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task FetchCosts( + SubscriptionFetchCostsParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } + + /// + public async Task FetchCosts( + string subscriptionID, + SubscriptionFetchCostsParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.FetchCosts( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task FetchSchedule( + SubscriptionFetchScheduleParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var page = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + page.Validate(); + } + return new SubscriptionFetchSchedulePage(this, parameters, page); + } + + /// + public async Task FetchSchedule( + string subscriptionID, + SubscriptionFetchScheduleParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.FetchSchedule( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task FetchUsage( + SubscriptionFetchUsageParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var subscriptionUsage = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + subscriptionUsage.Validate(); + } + return subscriptionUsage; + } + + /// + public async Task FetchUsage( + string subscriptionID, + SubscriptionFetchUsageParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.FetchUsage( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task PriceIntervals( + SubscriptionPriceIntervalsParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task PriceIntervals( + string subscriptionID, + SubscriptionPriceIntervalsParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.PriceIntervals( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task RedeemCoupon( + SubscriptionRedeemCouponParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task RedeemCoupon( + string subscriptionID, + SubscriptionRedeemCouponParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.RedeemCoupon( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task SchedulePlanChange( + SubscriptionSchedulePlanChangeParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task SchedulePlanChange( + string subscriptionID, + SubscriptionSchedulePlanChangeParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.SchedulePlanChange( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task TriggerPhase( + SubscriptionTriggerPhaseParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task TriggerPhase( + string subscriptionID, + SubscriptionTriggerPhaseParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.TriggerPhase( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task UnscheduleCancellation( + SubscriptionUnscheduleCancellationParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task UnscheduleCancellation( + string subscriptionID, + SubscriptionUnscheduleCancellationParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.UnscheduleCancellation( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task UnscheduleFixedFeeQuantityUpdates( + SubscriptionUnscheduleFixedFeeQuantityUpdatesParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task UnscheduleFixedFeeQuantityUpdates( + string subscriptionID, + SubscriptionUnscheduleFixedFeeQuantityUpdatesParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.UnscheduleFixedFeeQuantityUpdates( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task UnschedulePendingPlanChanges( + SubscriptionUnschedulePendingPlanChangesParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task UnschedulePendingPlanChanges( + string subscriptionID, + SubscriptionUnschedulePendingPlanChangesParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + return await this.UnschedulePendingPlanChanges( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task UpdateFixedFeeQuantity( + SubscriptionUpdateFixedFeeQuantityParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task UpdateFixedFeeQuantity( + string subscriptionID, + SubscriptionUpdateFixedFeeQuantityParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.UpdateFixedFeeQuantity( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } + + /// + public async Task UpdateTrial( + SubscriptionUpdateTrialParams parameters, + CancellationToken cancellationToken = default + ) + { + if (parameters.SubscriptionID == null) + { + throw new OrbInvalidDataException("'parameters.SubscriptionID' cannot be null"); + } + + HttpRequest request = new() + { + Method = HttpMethod.Post, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var mutatedSubscription = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + mutatedSubscription.Validate(); + } + return mutatedSubscription; + } + + /// + public async Task UpdateTrial( + string subscriptionID, + SubscriptionUpdateTrialParams parameters, + CancellationToken cancellationToken = default + ) + { + return await this.UpdateTrial( + parameters with + { + SubscriptionID = subscriptionID, + }, + cancellationToken + ); + } +} diff --git a/src/Orb/Services/TopLevelService.cs b/src/Orb/Services/TopLevelService.cs new file mode 100644 index 00000000..a7e97cd6 --- /dev/null +++ b/src/Orb/Services/TopLevelService.cs @@ -0,0 +1,51 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Orb.Core; +using Orb.Models.TopLevel; + +namespace Orb.Services; + +/// +public sealed class TopLevelService : ITopLevelService +{ + /// + public ITopLevelService WithOptions(Func modifier) + { + return new TopLevelService(this._client.WithOptions(modifier)); + } + + readonly IOrbClient _client; + + public TopLevelService(IOrbClient client) + { + _client = client; + } + + /// + public async Task Ping( + TopLevelPingParams? parameters = null, + CancellationToken cancellationToken = default + ) + { + parameters ??= new(); + + HttpRequest request = new() + { + Method = HttpMethod.Get, + Params = parameters, + }; + using var response = await this + ._client.Execute(request, cancellationToken) + .ConfigureAwait(false); + var deserializedResponse = await response + .Deserialize(cancellationToken) + .ConfigureAwait(false); + if (this._client.ResponseValidation) + { + deserializedResponse.Validate(); + } + return deserializedResponse; + } +} diff --git a/src/Orb/Shims.cs b/src/Orb/Shims.cs new file mode 100644 index 00000000..afd5582f --- /dev/null +++ b/src/Orb/Shims.cs @@ -0,0 +1,41 @@ +using System; + +#if !NET +#pragma warning disable IDE0130 // Namespace does not match folder structure +#pragma warning disable CS9113 // Unused parameters + +namespace System.Runtime.CompilerServices +{ + // Allow `required` to compile when targeting .NET Standard 2.0. + [AttributeUsage( + AttributeTargets.Class + | AttributeTargets.Struct + | AttributeTargets.Property + | AttributeTargets.Field, + AllowMultiple = false, + Inherited = false + )] + internal sealed class RequiredMemberAttribute : Attribute; + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + internal sealed class CompilerFeatureRequiredAttribute(string feature) : Attribute; + + // Allow `init` to compile when targeting .NET Standard 2.0. + internal static class IsExternalInit; +} + +namespace System.Diagnostics.CodeAnalysis +{ + // Allow `[SetsRequiredMembers]` to compile when targeting .NET Standard 2.0. + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] + internal sealed class SetsRequiredMembersAttribute : Attribute; + + // Allow `[MaybeNullWhen(...)]` to compile when targeting .NET Standard 2.0. + [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] + internal sealed class MaybeNullWhenAttribute(bool returnValue) : Attribute; + + // Allow `[NotNullWhen(...)]` to compile when targeting .NET Standard 2.0. + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + internal sealed class NotNullWhenAttribute(bool returnValue) : Attribute; +} +#endif